for 循环到 unlist(),选择向量元素并转换类 - 循环、列表、向量、选择

Posted

技术标签:

【中文标题】for 循环到 unlist(),选择向量元素并转换类 - 循环、列表、向量、选择【英文标题】:for loop to unlist(), select vector element & convert class - loops, list, vector, selection 【发布时间】:2022-01-22 08:28:39 【问题描述】:

我在概括处理一些“问题数据”(列表的矢量化元素)的方法时遇到了问题。 (我不完全确定我是否准确地描述了这一点,所以请原谅我的无知)。

目标:

我正在尝试编译一个自动处理以下问题的函数,因为目的是重复运行/利用此方法。

问题:

我已经通过单位名称(传感器来自的设备)从数据库中提取了一些传感器数据,通常传感器数据以向量的形式出现(根据所需的结果 - 如下),但对于某些单位(数据收集器的配置不同)它返回一个向量列表。

向量中的元素数量与现场单元的数量有关(即如果现场有两个单元,/01 和 /02,那么向量将包含 2 个元素....等等)

我只想将与该单元相关的传感器数据保存在相关列中。

并非所有单元都以相同的方式配置,所以我只打算在确认列的类是一个列表时运行一个函数。

传感器的数量和标签每次都会不同(输入到主函数中)。

预期方法:

    对每列执行以下检查和纠正措施 检查列类 - 检查类是否为“列表” 如果为 FALSE,则什么也不做。 如果为 TRUE,则使用“unlist_func”(子函数)对每一行执行以下操作: 检查'unit'列每一行的文本字符串的结尾并提取unit_no 取消列出当前元素,选择向量中与unit列中unit_no对应的数字 将列类修改为

可重现的问题:

以下小标题是我正在使用的示例:

unit <- c('a2b7/01', 'a2b7/02', 'a2b7/03', 'a2b7/01', 'a2b7/02', 'a2b7/03', 'a2b7/01', 'a2b7/02', 'a2b7/03')
sen1 <- list(c(1,2,3), c(4,5,6), c(7,8,9), c(10,11,12), c(13,14,15), c(16,17,18), c(19,20,21), c(22,23,24), c(25,26,27))
sen2 <- list(1, 2, 3, 4, 5, 6, 7, 8, 9)

sensor_data <- tibble(unit, sen1, sen2)

期望的结果:

unit <- c('a2b7/01', 'a2b7/02', 'a2b7/03', 'a2b7/01', 'a2b7/02', 'a2b7/03', 'a2b7/01', 'a2b7/02', 'a2b7/03')
sen1 <- c(1,5,9,10,14,19,23,27)
sen2 <- c(1, 2, 3, 4, 5, 6, 7, 8, 9)

sensor_data_new <- tibble(unit, sen1, sen2)

到目前为止的尝试和请求:

为了避免空手而归,我已经发布了我预期方法的草率版本,但我很抱歉,这是一项正在进行的工作,我感谢其中存在错误,但我希望能吸引那些在那里的人尽可能提供帮助或建议不同的方法。

所有建议将不胜感激。

function(unit, sensors, date_from, date_to)
  
  #  ------  QUERYING TASK  ------------------------
  
  sensor_data       <- 'pulls sensor info from unit names'
  
  #  ------  SUB FUNCTION - Unlist function  -------
  
  unlist_func <-  function(df = sensor_data, j)
  
                  sensor_data_distinct <- df %>% 
                                          mutate(unit_no = str_extract(unit, '\\d$')) %>%
                                          select(unit_no) %>% 
                                          distinct()

                  for (i in 1:nrow(df))
                  
                    if(length(df[, j[[i]] ]) => 1 & str_ends(df$unit, sensor_data_distinct$unit_no))
                        unlist(df[i, j])
                        df[sensor_data_distinct$unit_no]
                     else(sensor_data[, j])
                  

  #  -------  STAGE 1 CLEANSING FUNCTION  -------------
  # unit will always be in column 1 and datetime always in column 2
  stg1_cleanse    <- for(j in 3:ncol(sensor_data))        # for-loop over columns
                        if (is.list(sensor_data[, j]) == TRUE)
                         lapply(unlist_func.....)
                        
                      
                  
  
  #  -------  STAGE 1 CLEANSING FUNCTION  -------------
                        
  stg2_cleanse    <- 'further cleansing routine'
  

【问题讨论】:

【参考方案1】:

我认为您可以大大简化您的功能。这似乎会产生您想要的结果。自定义函数extract_func 实现了检查每行长度的规则。如果是单元素值,则返回单元素;如果它是向量,则返回请求索引处的元素。然后我们可以使用 dplyr 的 rowwiseacross 函数将此函数应用于列“sen1”和“sen2”,传递“unit_num”作为索引参数(在需要时)。

library(tidyverse)

unit <- c('a2b7/01', 'a2b7/02', 'a2b7/03', 'a2b7/01', 'a2b7/02', 'a2b7/03', 'a2b7/01', 'a2b7/02', 'a2b7/03')
sen1 <- list(c(1,2,3), c(4,5,6), c(7,8,9), c(10,11,12), c(13,14,15), c(16,17,18), c(19,20,21), c(22,23,24), c(25,26,27))
sen2 <- list(1, 2, 3, 4, 5, 6, 7, 8, 9)

sensor_data <- tibble(unit, sen1, sen2)

extract_func <- function(data, idx) 

  # check for NULL data and convert to NA if it is present
  if (is.null(data)) 
      data <- NA
  
  
  if (length(data) == 1) 
    return(data[1])
   else 
    return(data[idx])
  
  


sensor_data_clean <- sensor_data %>% 
  rowwise() %>% 
  mutate(
    unit_num = as.numeric(str_extract(unit, '\\d$')),
    across(c(sen1, sen2), ~extract_func(., unit_num), .names = 'extract_.col')
  )

# A tibble: 9 × 6
# Rowwise: 
  unit    sen1      sen2      unit_num extract_sen1 extract_sen2
  <chr>   <list>    <list>       <dbl>        <dbl>        <dbl>
1 a2b7/01 <dbl [3]> <dbl [1]>        1            1            1
2 a2b7/02 <dbl [3]> <dbl [1]>        2            5            2
3 a2b7/03 <dbl [3]> <dbl [1]>        3            9            3
4 a2b7/01 <dbl [3]> <dbl [1]>        1           10            4
5 a2b7/02 <dbl [3]> <dbl [1]>        2           14            5
6 a2b7/03 <dbl [3]> <dbl [1]>        3           18            6
7 a2b7/01 <dbl [3]> <dbl [1]>        1           19            7
8 a2b7/02 <dbl [3]> <dbl [1]>        2           23            8
9 a2b7/03 <dbl [3]> <dbl [1]>        3           27            9

由于您只是检查向量的长度然后提取单个元素,因此您可以在 mutate 内执行以下内联操作(尽管像上面这样的预定义自定义函数为您未来提供了更多的灵活性) .

sensor_data_clean <- sensor_data %>% 
  rowwise() %>% 
  mutate(
    unit_num = as.numeric(str_extract(unit, '\\d$')),
    across(c(sen1, sen2), ~(.[min(length(.), unit_num)]), .names = 'extract_.col')
  )

【讨论】:

谢谢你,看来我把问题复杂化了。就 cross() 方面而言,我希望能够将其应用于“列表”类的任何 cloumn。我可以只使用cross(.cols = is.list(), ....... 吗?或者使用cross(.cols = Everything()....如果它正在寻找大于1的长度跨度> across(.cols = where(is.list), ... ) 可能是你想要的。 啊,是的,完美。非常感谢您 嗨,如果可以的话,只是为了扩展这个问题:) 如果列表的向量元素之一中存在 NULL 值,则似乎存在问题,呈现这一点。为了处理这些 NULL 值,我打算使用线性插值函数,但我需要首先解决提取单个值的问题。我可以删除 NULL 但理想情况下我不想这样做。如果您有任何建议,将再次受到欢迎? ie...sen1

以上是关于for 循环到 unlist(),选择向量元素并转换类 - 循环、列表、向量、选择的主要内容,如果未能解决你的问题,请参考以下文章

使用R语言将不同长度的向量合并为数据框

通过for循环将值附加到向量不起作用

附加到数据帧中特定值的 for 循环中的向量

为啥需要两个范围 for 循环来更改 C++ 中向量的这些元素?

在函数调用中使用 unlist

For循环迭代不断增长的向量