在 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
,因为cbind
将vector
s 绑定到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 中聚合到字符串并对与聚合关联的值求和的主要内容,如果未能解决你的问题,请参考以下文章