在 R 3.3.0 Dplyr v 0.5.0 中聚合到字符串并对与聚合关联的值求和

Posted

技术标签:

【中文标题】在 R 3.3.0 Dplyr v 0.5.0 中聚合到字符串并对与聚合关联的值求和【英文标题】:Aggregating to String and Summing the Values Associated to Aggregate in R 3.3.0 Dplyr v 0.5.0 【发布时间】:2017-01-08 16:29:13 【问题描述】:

问题:

我有以下要简化的数据框

Fruit <-  c("Apple","Apple","Orange","Orange","Banana","Banana")
Farmer <- c("Bob","Ben","Bill","Bob","George","Bob")
Tons.Jan <- c(20,40,10,20,35,15)
Tons.Feb <- c(30,40,20,15,25,30)
Tons.Mar <- c(10,10,15,10,20,30)
Tons.Apr <- c(15,20,15,30,30,30)
Tons.May <- c(20,5,20,20,20,10)

df <- cbind(Fruit,Farmer)
df <- cbind(df,Tons.Jan)
df <- cbind(df,Tons.Feb)
df <- cbind(df,Tons.Mar)
df <- cbind(df,Tons.Apr)
df <- tbl_df(cbind(df,Tons.May))

我希望能够将 Farmers 总结为一个逗号分隔的强项,并将 Tons 与观察结果相加,使其如下所示

我想达到以下目标

Fruit2 <- c("Apple","Orange","Banana")
Farmer2 <- c("Bob,Ben","Bill,Bob","George,Bob")
Tons.Jan2 <- c(60,30,50)
Tons.Feb2 <- c(70,35,55)
Tons.Mar2 <- c(20,25,50)
Tons.Apr2 <- c(35,45,60)
Tons.May2 <- c(25,40,30)

df2 <- cbind(Fruit2,Farmer2)
df2 <- cbind(df2,Tons.Jan2)
df2 <- cbind(df2,Tons.Feb2)
df2 <- cbind(df2,Tons.Mar2)
df2 <- cbind(df2,Tons.Apr2)
df2 <- tbl_df(cbind(df2,Tons.May2))

我尝试过的:

我尝试在下面使用 dplyr 函数 group_by 和 summarise_each

df <- df %>% group_by(Fruit) %>%
   summarise_each_(funs(toString))

但是我不确定如何在不使用汇总函数专门调用每一列的情况下对数值求和进行积分,

感谢任何帮助。

【问题讨论】:

【参考方案1】:

最好不要使用data.frame(cbind(tbl_df(cbind,因为cbindvectors 绑定到matrix 并且矩阵只能包含一个类,所以当我们将matrix 更改为data.frame(使用默认选项,即 stringsAsFactors=TRUE),如果有 any 字符 vector,则 matrix 将是所有 character 类列,并且随着列的增加,这种情况会变得更糟现在 factor 类与 data.frame 转换。因此,我们不必要地使用as.numeric(as.character( 来更改numeric 列的type。最好将'data.frame'构造为

data.frame(Fruit, Farmer, Tons.Jan, ...)

data.table 解决方案是

library(data.table)
setDT(df)[,  Farmer :=  toString(Farmer), by = Fruit][ , 
     lapply(.SD, function(x) sum(as.numeric(as.character(x)))) , .(Fruit, Farmer)]
#    Fruit                   Farmer Tons.Jan Tons.Feb Tons.Mar Tons.Apr Tons.May
#1:  Apple       Bob, Ben, Bob, Ben       60       70       20       35       25
#2: Orange     Bill, Bob, Bill, Bob       30       35       25       45       40
#3: Banana George, Bob, George, Bob       50       55       50       60       30

此外,这可以通过按“水果”分组(基于 OP 的输出)一步完成

setDT(df)[, c(Farmer = toString(Farmer), lapply(.SD[, 
   setdiff(names(.SD), "Farmer"), with = FALSE], 
       function(x) sum(as.numeric(as.character(x))))), .(Fruit)]
#    Fruit      Farmer Tons.Jan Tons.Feb Tons.Mar Tons.Apr Tons.May
#1:  Apple    Bob, Ben       60       70       20       35       25
#2: Orange   Bill, Bob       30       35       25       45       40
#3: Banana George, Bob       50       55       50       60       30

【讨论】:

感谢您的提示。我会继续使用它。【参考方案2】:
library(dplyr)

# Convert the relevant columns to numeric
df <- mutate_each(df, funs(as.numeric), -Fruit, -Farmer)

# or as mentioned in the comments by jazzurro
df <- mutate_at(df, vars(starts_with("Tons")), as.numeric)

df %>% 
    group_by(Fruit) %>% 
    mutate(Farmer = toString(Farmer)) %>%
    group_by(Fruit, Farmer) %>%
    summarise_all(funs(sum))


#Source: local data frame [3 x 7]
#Groups: Fruit [?]
#
#   Fruit      Farmer Tons.Jan Tons.Feb Tons.Mar Tons.Apr Tons.May
#   <chr>       <chr>    <dbl>    <dbl>    <dbl>    <dbl>    <dbl>
#1  Apple    Bob, Ben       60       70       20       35       25
#2 Banana George, Bob       50       55       50       60       30
#3 Orange   Bill, Bob       30       35       25       45       40

【讨论】:

我认为你可以用mutate(Farmer = toString(Farmer)) 覆盖Farmer。最后一步目前可以写成summarize_each(funs(sum(.)))。将来,summarize_each 似乎已被弃用。所以我认为使用summarize_all 是一件好事。还有一件事。为了将字符转换为数字,您也可以使用mutate_at(df, vars(starts_with("Tons")), as.numeric) 是的,即将覆盖农夫!谢谢! 这行得通!我使用 jazzurro 的建议来覆盖 Farmer 变量。谢谢!

以上是关于在 R 3.3.0 Dplyr v 0.5.0 中聚合到字符串并对与聚合关联的值求和的主要内容,如果未能解决你的问题,请参考以下文章

在 dplyr 的函数中使用变量名

R:向向量的某些索引添加值

在 dplyr (R) 中添加“count where”

基于Python 的简单推荐系统

r/dplyr:在 UDF 中使用动态命名的变量

在 R / dplyr 中循环完全连接