【问题标题】:dplyr rowwise sum and other functions like maxdplyr 按行求和和其他函数,如 max
【发布时间】:2018-08-29 23:29:30
【问题描述】:

如果我想使用 dplyr 对数据框中的一些变量求和,我可以这样做:

> head(iris)
  Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1          5.1         3.5          1.4         0.2  setosa
2          4.9         3.0          1.4         0.2  setosa
3          4.7         3.2          1.3         0.2  setosa
4          4.6         3.1          1.5         0.2  setosa
5          5.0         3.6          1.4         0.2  setosa
6          5.4         3.9          1.7         0.4  setosa

> select(iris, starts_with('Petal')) %>% rowSums()
  [1] 1.6 1.6 1.5 1.7 1.6 2.1 1.7 1.7 1.6 1.6 1.7 1.8 1.5 1.2 1.4 1.9 1.7 1.7 2.0 1.8 1.9 1.9 1.2 2.2 2.1 1.8 2.0 1.7 1.6 1.8 1.8 1.9 1.6 1.6 1.7 1.4
 [37] 1.5 1.5 1.5 1.7 1.6 1.6 1.5 2.2 2.3 1.7 1.8 1.6 1.7 1.6 6.1 6.0 6.4 5.3 6.1 5.8 6.3 4.3 5.9 5.3 4.5 5.7 5.0 6.1 4.9 5.8 6.0 5.1 6.0 5.0 6.6 5.3
 [73] 6.4 5.9 5.6 5.8 6.2 6.7 6.0 4.5 4.9 4.7 5.1 6.7 6.0 6.1 6.2 5.7 5.4 5.3 5.6 6.0 5.2 4.3 5.5 5.4 5.5 5.6 4.1 5.4 8.5 7.0 8.0 7.4 8.0 8.7 6.2 8.1
[109] 7.6 8.6 7.1 7.2 7.6 7.0 7.5 7.6 7.3 8.9 9.2 6.5 8.0 6.9 8.7 6.7 7.8 7.8 6.6 6.7 7.7 7.4 8.0 8.4 7.8 6.6 7.0 8.4 8.0 7.3 6.6 7.5 8.0 7.4 7.0 8.2
[145] 8.2 7.5 6.9 7.2 7.7 6.9

这很好,但我原以为rowwise 完成了同样的事情,但事实并非如此,

> select(iris, starts_with('Petal')) %>% rowwise() %>% sum()
[1] 743.6

我特别想做的是选择一组列,并创建一个新变量,每个变量的值都是所选列的每一行的最大值。例如,如果我选择“花瓣”列,最大值将为 1.4、1.4、1.3 等。

我可以这样做:

> select(iris, starts_with('Petal')) %>% apply(1, max)

这很好。但我只是好奇为什么rowwise 方法不起作用。我意识到我错误地使用了rowwise,我只是不确定为什么它是错误的。

【问题讨论】:

    标签: r dataframe dplyr rowwise


    【解决方案1】:

    简而言之:您希望“sum”函数能够识别dplyr 数据结构,例如按行分组的数据框。 sum 不知道它,所以它只取整个 data.frame 的总和。

    这里是一个简短的解释。这个:

    select(iris, starts_with('Petal')) %>% rowwise() %>% sum()
    

    可以在不使用管道运算符的情况下重写如下:

    data <- select(iris, starts_with('Petal'))
    data <- rowwise(data)
    sum(data)
    

    如您所见,您正在构建一个名为tibble 的东西。然后rowwise 调用添加有关此对象的附加信息并指定它应该按行分组。

    但是,只有 summarizemutate 等知道这种分组的函数才能按预期工作。像 sum 这样的基本 R 函数不知道这些对象,并将它们视为任何标准 data.frames。而sum() 的标准方法是对整个数据框求和。

    使用mutate 有效:

    select(iris, starts_with('Petal')) %>%
      rowwise() %>%
      mutate(sum = sum(Petal.Width, Petal.Length))
    

    结果:

    Source: local data frame [150 x 3]
    Groups: <by row>
    
    # A tibble: 150 x 3
       Petal.Length Petal.Width   sum
              <dbl>       <dbl> <dbl>
     1         1.40       0.200  1.60
     2         1.40       0.200  1.60
     3         1.30       0.200  1.50
     ...
    

    【讨论】:

      【解决方案2】:

      问题在于,尽管rowwise,整个数据帧仍以点的形式传递。要处理此问题,请使用 do ,它将 dot 解释为仅表示当前行。另一个问题是do 中的点会将行表示为列表,因此请适当地转换它。

      library(dplyr)
      
      iris %>%
        slice(1:6) %>%
        select(starts_with('Petal')) %>% 
        rowwise() %>%
        do( (.) %>% as.data.frame %>% mutate(sum = sum(.)) ) %>%
        ungroup
      

      给予:

      # A tibble: 6 x 3
        Petal.Length Petal.Width   sum
      *        <dbl>       <dbl> <dbl>
      1         1.40       0.200  1.60
      2         1.40       0.200  1.60
      3         1.30       0.200  1.50
      4         1.50       0.200  1.70
      5         1.40       0.200  1.60
      6         1.70       0.400  2.10
      

      dplyr 1.0 - 稍后添加

      既然有人问过这个问题,dplyr 1.0 已经发布,它有cur_data(),可用于简化上述操作,从而无需dorowwise 块内的 cur_data() 仅指当前行。

      iris %>%
        slice(1:6) %>%
        select(starts_with('Petal')) %>% 
        rowwise() %>%
        mutate(sum = sum(cur_data())) %>%
        ungroup
      

      【讨论】:

        【解决方案3】:

        如果你使用c_across来选择你想要求和的变量,你可以跳过select的使用:

        iris %>% 
          rowwise() %>% 
          mutate(sum = sum(c_across(starts_with("Petal"))), .keep = "used") %>% 
          ungroup()
        

        输出

        如果您想保留数据框中的所有列,请删除 .keep 参数。

         Petal.Length Petal.Width   sum
                  <dbl>       <dbl> <dbl>
         1          1.4         0.2   1.6
         2          1.4         0.2   1.6
         3          1.3         0.2   1.5
         4          1.5         0.2   1.7
         5          1.4         0.2   1.6
         6          1.7         0.4   2.1
         7          1.4         0.3   1.7
         8          1.5         0.2   1.7
         9          1.4         0.2   1.6
        10          1.5         0.1   1.6
        # ... with 140 more rows
        

        同样,max:

        iris %>% 
            rowwise() %>% 
            mutate(max = max(c_across(starts_with("Petal"))), .keep = "used") %>% 
            ungroup()
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2021-11-03
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-03-29
          • 1970-01-01
          • 2019-05-16
          相关资源
          最近更新 更多