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

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

目标:

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

问题:

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

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

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

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

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

预期方法:

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

可重现的问题:

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

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'
  
}

【问题讨论】:

    标签: r for-loop


    【解决方案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
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-11-11
    • 2019-04-06
    • 1970-01-01
    • 2015-03-24
    • 2014-08-01
    • 2019-05-17
    相关资源
    最近更新 更多