【问题标题】:Succinct subsetting across multiple columns in RR中跨多个列的简洁子集
【发布时间】:2020-06-13 04:57:29
【问题描述】:

假设我有一个庞大的数据框,并且在多个列中我有一个非常大的唯一代码列表,我想使用这些代码来选择某些行来子集原始数据框。大约有 1000 个代码,我希望所有代码都遵循。例如,我有大约 30 列包含代码,我只想在这些列中的任何一个中获取代码为 100 到 120 的行。

要做到这一点还有很长的路要走,就像

new_dat <- df[which(df$codes==100 | df$codes==101 | df$codes1==100 

我对每个可能包含这些代码的列的每个可能的代码重复此操作。有没有更方便的方式来做到这一点?

我想尝试使用dplyrselect 函数解决这个问题,但我无法确定它是否适用于我的情况

获取iris 数据集

假设我想要在列名中包含单词 Sepal 的任何列中包含值 4.0-5.0 的所有行。

#this only goes for 4.0

brand_new_df <- select(filter(iris, Sepal.Length ==4.0 | Sepal.Width == 4.0))

但我想要的是类似

brand_new_df <- select(filter(iris, contains(Sepal) == 4.0:5.0))

有没有 dplyr 方法可以做到这一点?

【问题讨论】:

    标签: r dplyr


    【解决方案1】:

    @RonakShah 的回答中对应的across() 版本:

    library(dplyr)
    
    iris %>% filter(rowSums(across(contains('Sepal'), ~ between(., 4, 5))) > 0)
    

    iris %>% filter(rowSums(across(contains('Sepal'), between, 4, 5)) > 0)
    

    来自vignette("colwise")

    以前,filter()all_vars()any_vars() 助手配对。现在,across() 等同于 all_vars(),并且没有直接替代 any_vars()

    所以你需要rowSums(...) &gt; 0之类的东西来达到any_vars()的效果。

    【讨论】:

      【解决方案2】:

      你可以使用filter_at

      library(dplyr)
      iris %>%  filter_at(vars(contains('Sepal')), any_vars(between(., 4, 5)))
      
      #   Sepal.Length Sepal.Width Petal.Length Petal.Width    Species
      #1           4.9         3.0          1.4         0.2     setosa
      #2           4.7         3.2          1.3         0.2     setosa
      #3           4.6         3.1          1.5         0.2     setosa
      #4           5.0         3.6          1.4         0.2     setosa
      #5           4.6         3.4          1.4         0.3     setosa
      #6           5.0         3.4          1.5         0.2     setosa
      #7           4.4         2.9          1.4         0.2     setosa
      #....
      

      【讨论】:

      • 酷!假设我还想为我选择的代码添加一个跳转,不仅包括 4 到 5,还包括 5.5 到 6。我该怎么做?此外,我尝试了仅使用 any_vars 函数和 new_dat = iris %&gt;% filter_at(vars(contains('Sepal')), any_vars(4)) 的方法,但这会返回整个数据框,而不是所选列中只有 4 个的行。是不是我做错了什么
      • @762 你的意思是iris %&gt;% filter_at(vars(contains('Sepal')), any_vars(between(., 4, 5) | between(., 5.5, 6))) 吗?
      • 没错!除了 between 方法之外,它还能以其他方式应用吗?就像any_vars(4 | 4.1) 获取具有 4 或 4.1 的值?我试过了,但只是将完整的数据框返回给我。
      • 是的,您可以使用iris %&gt;% filter_at(vars(contains('Sepal')), any_vars(. %in% c(4, 4.1))) 并在c() 中添加您想要的所有数字,但请记住浮点比较不准确。阅读stackoverflow.com/questions/9508518/…
      【解决方案3】:

      基础R:

      # Subset: 
      cols <- grep("codes", names(df2), value = TRUE)
      df2[rowSums(sapply(cols,
                         function(x) {
                           df2[, x] >= 100 & df2[, x] <= 120
                         })) == length(cols), ]
      # Data: 
      tmp <- data.frame(x1 <- rnorm(999, mean = 100, sd = 2))
      df <-
        setNames(data.frame(tmp[rep(1, each = 80)]), paste0("codes", 1:80))
      df2 <- cbind(id = 1:nrow(df), df)
      

      【讨论】:

        【解决方案4】:

        一个选项可能是:

        iris %>%
         filter(Reduce(`|`, across(contains("Sepal"), ~ between(.x, 4, 5))))
        
           Sepal.Length Sepal.Width Petal.Length Petal.Width Species
        1           4.9         3.0          1.4         0.2       1
        2           4.7         3.2          1.3         0.2       1
        3           4.6         3.1          1.5         0.2       1
        4           5.0         3.6          1.4         0.2       1
        5           4.6         3.4          1.4         0.3       1
        6           5.0         3.4          1.5         0.2       1
        7           4.4         2.9          1.4         0.2       1
        8           4.9         3.1          1.5         0.1       1
        9           4.8         3.4          1.6         0.2       1
        10          4.8         3.0          1.4         0.1       1
        

        【讨论】:

          【解决方案5】:
          library(dplyr)
          df <- iris
          # value to look for
          val <- 4 
          # find columns
          cols <- which(colSums(df == val , na.rm = TRUE) > 0L)
          # filter rows
          iris %>%  filter_at(cols, any_vars(.==val))
            Sepal.Length Sepal.Width Petal.Length Petal.Width    Species
          1          5.8         4.0          1.2         0.2     setosa
          2          5.5         2.3          4.0         1.3 versicolor
          3          6.0         2.2          4.0         1.0 versicolor
          4          6.1         2.8          4.0         1.3 versicolor
          5          5.5         2.5          4.0         1.3 versicolor
          6          5.8         2.6          4.0         1.2 versicolor
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2018-04-19
            • 2014-05-09
            • 2019-07-11
            • 2022-08-18
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多