【问题标题】:R: Minimum and maximum values by row with unknown number of columnsR:列数未知的行的最小值和最大值
【发布时间】:2018-08-25 06:58:21
【问题描述】:

对于数据框,我需要逐行查找从第 2 列开始的未知列数的最小值和最大值。这是一个例子:

library(tidyverse)

# test data
(test_data <- tibble(id = c(1:9), 
                     x = runif(9), 
                     x2 = runif(9),
                     x3 = runif(9)))
samples = 100    

# This example, which specifies the column names, correctly finds the min and max values by row
(test_1 <- test_data %>% 
  rowwise() %>%
  mutate(min_val = min(x, x2, x3), max_val = max(x, x2, x3)))

# This example does not
(test_2 <- test_data %>% 
    rowwise() %>%
    mutate(min_val = min(x:x3), max_val = max(x:x3)))

我真正想做的是像

mutate(min_val = min([,2:samples+1]), max_val = max([,2:samples+1])))

因为 (1) 我希望保留 id 列(以便稍后与另一个数据框连接),并且 (2) 按列位置指定似乎是一种明显的方法,因为我不关心列名和样本可能很大。

谢谢!

编辑示例

这个(按照建议)

test_data %>%
  nest(-id) %>%                         # nest rest of columns apart from id
  mutate(min_val = map(data, min),      # get min and max
         max_val = map(data, max)) %>%
  unnest()   

处理原始测试数据。然而,现实世界的数据有重复的id,例如

(test_data <- tibble(id = c(1:9, 1:9), 
                     x = runif(18), 
                     x2 = runif(18),
                     x3 = runif(18)))

这会导致“错误:所有嵌套列必须具有相同数量的元素。”。

【问题讨论】:

    标签: r dplyr


    【解决方案1】:

    一个可能的tidyverse 解决方案是nest 除了id 之外的任何列,然后使用map 得到minmax。您无需指定任何列名:

    library(tidyverse)
    
    # test data
    (test_data <- tibble(id = c(1:9), 
                         x = runif(9), 
                         x2 = runif(9),
                         x3 = runif(9)))
    samples = 100    
    
    test_data %>%
      nest(-id) %>%                         # nest rest of columns apart from id
      mutate(min_val = map(data, min),      # get min and max
             max_val = map(data, max)) %>%
      unnest()                              # unnest columns
    
    # # A tibble: 9 x 6
    #      id min_val max_val      x     x2    x3
    #   <int>   <dbl>   <dbl>  <dbl>  <dbl> <dbl>
    # 1     1  0.0217   0.239 0.130  0.0217 0.239
    # 2     2  0.125    0.814 0.625  0.814  0.125
    # 3     3  0.281    0.770 0.331  0.770  0.281
    # 4     4  0.123    0.868 0.123  0.644  0.868
    # 5     5  0.149    0.340 0.149  0.340  0.337
    # 6     6  0.496    0.865 0.596  0.865  0.496
    # 7     7  0.0766   0.984 0.0766 0.656  0.984
    # 8     8  0.272    0.926 0.702  0.926  0.272
    # 9     9  0.433    0.912 0.912  0.433  0.590
    

    在有多个 id 的情况下,你可以使用这个:

    test_data %>%
      mutate(row_id = row_number()) %>%     # create a row identifier
      nest(-id, -row_id) %>%                # nest rest of columns apart from id and row id
      mutate(min_val = map(data, min),      # get min and max
             max_val = map(data, max)) %>%
      unnest()                              # unnest columns
    

    【讨论】:

    • 请注意,您无需致电group_by()。只需改用nest(-id)
    • 谢谢。我习惯了group_bynest,但从现在开始会改变它:)
    • 感谢您不仅回答了这个问题,而且还向我展示了在这种情况下如何使用地图(我一直在尝试使用它来获得逐行的最小值和最大值,感觉它会是更好的方法,但没有成功)。此示例在测试日完美运行。但是,在我的真实数据集上,我收到“错误:所有嵌套列必须具有相同数量的元素”。这似乎是因为 id 列具有重复的 id 值(我已经适当地编辑了原始问题)。谢谢
    • 您可以通过df &lt;- tibble::rowid_to_column(df, "id_uni")为所有行分配唯一ID
    • 我已经更新了我的答案。我正在使用 row_number 创建一个唯一的 id,但 rowid_to_column 也非常好。
    【解决方案2】:

    这是pmin/pmax 的一个选项

    library(tidyverse)
    test_data %>% 
         mutate(min_val = pmin(!!! rlang::syms(names(.)[-1])),
                max_val = pmax(!!! rlang::syms(names(.)[-1])))
    # A tibble: 9 x 6
    #     id     x     x2     x3 min_val max_val
    #  <int> <dbl>  <dbl>  <dbl>   <dbl>   <dbl>
    #1     1 0.293 0.255  0.501   0.255    0.501
    #2     2 0.225 0.605  0.139   0.139    0.605
    #3     3 0.704 0.371  0.0939  0.0939   0.704
    #4     4 0.519 0.672  0.552   0.519    0.672
    #5     5 0.663 0.673  0.725   0.663    0.725
    #6     6 0.920 0.320  0.138   0.138    0.920
    #7     7 0.280 0.904  0.223   0.223    0.904
    #8     8 0.764 0.198  0.688   0.198    0.764
    #9     9 0.802 0.0442 0.0765  0.0442   0.802
    

    数据

    set.seed(24)
    test_data <- tibble(id = c(1:9), 
                        x = runif(9), 
                        x2 = runif(9),
                        x3 = runif(9))
    

    【讨论】:

    • 谢谢您:这可以解决问题。它还可以使用 id = c(1:9, 1_9) 来解决问题,即使用重复的 id 变量,这正是我所需要的!它也适用于我的真实数据(>100,000 行)。我承认,但是我不理解语法'min_val = pmin(!!! rlang::syms(names(.)[-1]))'!
    • @Martino names(.)[-1] 给出数据集的列名,除了第一个列名作为字符串。它用syms 转换为symbol,然后评估(!!!) 以获得那些将pminpmax 应用于行明智的最小值或最大值的列的值。
    • 感谢您的解释(我至少部分理解!) - 我会进一步研究。
    猜你喜欢
    • 1970-01-01
    • 2013-06-05
    • 2015-07-02
    • 2015-01-09
    • 1970-01-01
    • 1970-01-01
    • 2015-07-29
    • 2020-07-07
    • 2021-08-02
    相关资源
    最近更新 更多