【问题标题】:check which columns in list have exact string value and extract the column and row检查列表中的哪些列具有确切的字符串值并提取列和行
【发布时间】:2020-08-31 18:41:04
【问题描述】:

我有这个数据框:

df <- data.frame (
  A = c("ABC11234","ABC11"),
  B = c(11,1),
  C = c("11",11),
  D =  c(11.1,"11.1"))

我应用这个函数来告诉我哪些行和列有这个确切的字符串并将输出分配给'a'

a<- lapply(df, function(x) grep("^11$",x))

现在我得到了一份清单,我想:

  1. 提取对(列 [名称] 和行 [值]),以便我可以准确地知道哪一列、哪一行具有我在 lapply 中查找的确切字符串。

在上面带有 grep 的 DF 示例中,我想知道 B = 1 和 C = 1,2(例如,B 列/第 1 行和 C 列/第 1 行和第 2 行的值为“^11$” )

我尝试过执行 a == integer(0) 或 unlist(a) 之类的操作,但我卡住了。

【问题讨论】:

    标签: r


    【解决方案1】:

    在我看来,您想要的输出只是包含您想要的“字符串”的那些列中的列名和行号。目前尚不清楚是否要避免包含数字 11,因为字符串函数会将数字强制转换为字符串。然而,这是我使用 stringr 包而不是 base 的解决方案。我首先提取满足您的正则表达式的所有元素(即整个“字符串”是"11"

        library(stringr)
        d <- lapply(df, function(x) str_extract_all(x,"^11$"))
    

    这会生成一个长度等于数据框列数的列表。列表中的每个元素与列中的行数相同,并且是"11"character(0)。现在我们获取列表中满足长度大于 0 条件的所有元素的索引(即您想要的字符串至少出现在列中一次)。

        lapply(d, function (x) which(x>0))
    

    这会生成另一个长度为 4 的列表。每个元素都是一个向量,其中包含满足您条件的每一列的行号。

    让我们取消列出这个

        e <- unlist(lapply(d, function (x) which(x>0)))
    

    这会产生一个命名向量,其中向量中的项目是行号,名称是列:

        B C1 C2 
        2  1  2 
    

    为了消除重复的列名(C1、C2 等),我们将再执行一个字符串函数来替换任何列名,然后将一个字母替换为仅列名:

        names(e) <- str_replace_all(names(e),"([A-Z])\\d","\\1")
    

    e 的输出是:

        B C C 
        1 1 2 
    

    所有代码放在一起:

        library(stringr)
        d <- lapply(df, function(x) str_extract_all(x,"^11$"))
        lapply(d, function (x) which(x>0))
        e<- unlist(lapply(d, function (x) which(x>0)))
        names(e) <- str_replace_all(names(e),"([A-Z])\\d","\\1")
        e
    

    【讨论】:

      【解决方案2】:

      另一种选择是重塑为“长”格式,然后获取相应的列名

      library(dplyr)
      library(tidyr)
      library(stringr)
      df %>% 
          mutate(across(everything(), as.character), row = row_number()) %>%
          pivot_longer(cols = -row, names_to = 'col') %>%
          group_by(row) %>% 
          summarise(col = unique(col[str_detect(value, '^11$')]), .groups = 'drop')
      # A tibble: 3 x 2
      #    row col  
      #  <int> <chr>
      #1     1 B    
      #2     1 C    
      #3     2 C    
      

      【讨论】:

        【解决方案3】:

        我不确定您是否想要以下内容

        a <- transform(
          as.data.frame(
            which(matrix(grepl("^11$", as.matrix(df)), nrow = nrow(df)),
            arr.ind = TRUE
          )),
          col = names(df)[col]
        )
        

        给了

        > a
          row col
        1   1   B
        2   1   C
        3   2   C
        

        【讨论】:

          【解决方案4】:

          我建议使用lapply():

          #Data
          df <- data.frame (
            A = c("ABC11234","ABC11"),
            B = c(11,1),
            C = c("11",11),
            D =  c(11.1,"11.1"),stringsAsFactors = F)
          #List
          a<- lapply(df, function(x) grep("^11$",x))
          #List 2
          a[lapply(a,length)==0]
          

          输出:

          $A
          integer(0)
          
          $D
          integer(0)
          

          如果您想从 df 中提取该值,您可以这样做:

          df[,rownames(do.call(rbind,a[lapply(a,length)==0]))]
          

          输出:

                   A    D
          1 ABC11234 11.1
          2    ABC11 11.1
          

          【讨论】:

            猜你喜欢
            • 2019-04-20
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2019-08-05
            • 2013-08-29
            • 1970-01-01
            • 2022-11-28
            • 2021-10-20
            相关资源
            最近更新 更多