用 sum+product 在 R 中重铸
Recast in R with sum+product
我有一个如下所示的数据框:
x y value weight
10 1 red 1
3.4 5 blue 2
10 10 blue 0.5
3 8 blue 0.5
3 8 red 4
10 1 blue 1
3 8 blue 2
3 8 blue 0.25
我想重铸它,使每一行都是 "x" 和 "y" 的唯一组合,而列是每个不同值的 "weight" 的总和"value"。如果可能的话,我 也 想要包含 "value" 值的原始计数的列。所以对于这些数据将是:
x y red_count blue_count red_sum_of_weights blue_sum_of_weights
10 1 1 1 1 1
3.4 5 0 1 0 2
10 10 0 0 1 0.5
3 8 1 3 4 2.75
有没有办法用 reshape 或 reshape2 做到这一点?我可以用
计算值
dcast(data,x+y~value)
但我一直无法弄清楚如何让它以我想要的方式使用权重。我需要这个来处理任意数量的可能值级别和原始数据集中每个 x*y 组合的任意不同行数。我已经编写了自己的代码,只是使用 for 循环来执行此操作,但是它需要 非常 很长时间才能 运行 - 到目前为止已经花了 6 个小时来完成前 15 个600k 行数据集的百分比,这不是很实用!但我确定必须有一种方法可以使用现有功能来做到这一点?
非常感谢您的帮助!
您可以结合使用 dplyr
和 reshape2
函数来完成此操作。首先按x
、y
和value
进行分组(我们将后者的名称改为color
只是为了避免熔化后列名重复),然后计算count和每个子组的总和。然后 melt
将新计算的摘要放入 "long" 格式的结果。最后,dcast
得到你要求的"wide"格式。
library(reshape2)
library(dplyr)
df %>% group_by(x,y,color=value) %>%
summarise(count=n(), sum=sum(weight)) %>%
melt(id.var=c("x","y","color")) %>%
dcast(x + y ~ variable + color)
x y count_blue count_red sum_blue sum_red
1 3.0 8 3 1 2.75 4
2 3.4 5 1 NA 2.00 NA
3 10.0 1 1 1 1.00 1
4 10.0 10 1 NA 0.50 NA
另一种处理数据的方法table:
require(data.table)
count=dcast(df,x+y~paste(value,"_count",sep=""))
weights=dcast(df,x+y~paste(value,"_sum_of_weights",sep=""),value.var = "weight",fun.aggregate = sum)
result=merge(count,weights,by=c("x","y"))
结果:
x y blue_count red_count blue_sum_of_weights red_sum_of_weights
10.0 1 1 1 1.00 1
10.0 10 1 0 0.50 0
3.0 8 3 1 2.75 4
3.4 5 1 0 2.00 0
尽管我不得不承认如果我们可以在 dcast 中使用两个函数会简单得多。据说你可以,但我一直收到错误...
经过一些挖掘后,我在这个线程 reshape2: multiple results of aggregation function? 中找到了一个非常好的答案,它为 dcast 定义了一个包装函数,如下所示:
dcastMult <- function(data, formula, value.var = "value",
funs = list("min" = min, "max" = max)) {
require(reshape2)
if (is.null(names(funs)) | any(names(funs) == "")) stop("funs must be named")
Form <- formula(formula)
LHS <- as.character(Form[[2]])
if (length(LHS) > 1) LHS <- LHS[-1]
temp <- lapply(seq_along(funs), function(Z) {
T1 <- dcast(data, Form, value.var = value.var,
fun.aggregate=match.fun(funs[[Z]]), fill = 0)
Names <- !names(T1) %in% LHS
names(T1)[Names] <- paste(names(T1)[Names], names(funs)[[Z]], sep = "_")
T1
})
Reduce(function(x, y) merge(x, y), temp)
}
使用这个可爱的函数,我们得到如下结果:
result=dcastMult(df,x+y~value,funs = list("count"=length,"sum_of_weights"=sum),value.var = "weight")
另一个选项:
df %>%
group_by(x, y, value) %>%
summarise(count = n(), sum = sum(weight)) %>%
gather(key, val, -(x:value)) %>%
unite(newkey, value, key) %>%
spread(newkey, val)
给出:
#Source: local data frame [4 x 6]
#Groups: x, y [4]
#
# x y blue_count blue_sum red_count red_sum
#* <dbl> <int> <dbl> <dbl> <dbl> <dbl>
#1 3.0 8 3 2.75 1 4
#2 3.4 5 1 2.00 NA NA
#3 10.0 1 1 1.00 1 1
#4 10.0 10 1 0.50 NA NA
这是一个使用 data.table::dcast
的简单解决方案:
require(data.table)
dcast(dt, x + y ~ value, value.var = "weight", fun.aggregate = list(length, sum))
# x y weight_length_blue weight_length_red weight_sum_blue weight_sum_red
# 1: 3.0 8 3 1 2.75 4
# 2: 3.4 5 1 0 2.00 0
# 3: 10.0 1 1 1 1.00 1
# 4: 10.0 10 1 0 0.50 0
其中,
dt = fread('x y value weight
10 1 red 1
3.4 5 blue 2
10 10 blue 0.5
3 8 blue 0.5
3 8 red 4
10 1 blue 1
3 8 blue 2
3 8 blue 0.25
')
我有一个如下所示的数据框:
x y value weight
10 1 red 1
3.4 5 blue 2
10 10 blue 0.5
3 8 blue 0.5
3 8 red 4
10 1 blue 1
3 8 blue 2
3 8 blue 0.25
我想重铸它,使每一行都是 "x" 和 "y" 的唯一组合,而列是每个不同值的 "weight" 的总和"value"。如果可能的话,我 也 想要包含 "value" 值的原始计数的列。所以对于这些数据将是:
x y red_count blue_count red_sum_of_weights blue_sum_of_weights
10 1 1 1 1 1
3.4 5 0 1 0 2
10 10 0 0 1 0.5
3 8 1 3 4 2.75
有没有办法用 reshape 或 reshape2 做到这一点?我可以用
计算值dcast(data,x+y~value)
但我一直无法弄清楚如何让它以我想要的方式使用权重。我需要这个来处理任意数量的可能值级别和原始数据集中每个 x*y 组合的任意不同行数。我已经编写了自己的代码,只是使用 for 循环来执行此操作,但是它需要 非常 很长时间才能 运行 - 到目前为止已经花了 6 个小时来完成前 15 个600k 行数据集的百分比,这不是很实用!但我确定必须有一种方法可以使用现有功能来做到这一点?
非常感谢您的帮助!
您可以结合使用 dplyr
和 reshape2
函数来完成此操作。首先按x
、y
和value
进行分组(我们将后者的名称改为color
只是为了避免熔化后列名重复),然后计算count和每个子组的总和。然后 melt
将新计算的摘要放入 "long" 格式的结果。最后,dcast
得到你要求的"wide"格式。
library(reshape2)
library(dplyr)
df %>% group_by(x,y,color=value) %>%
summarise(count=n(), sum=sum(weight)) %>%
melt(id.var=c("x","y","color")) %>%
dcast(x + y ~ variable + color)
x y count_blue count_red sum_blue sum_red 1 3.0 8 3 1 2.75 4 2 3.4 5 1 NA 2.00 NA 3 10.0 1 1 1 1.00 1 4 10.0 10 1 NA 0.50 NA
另一种处理数据的方法table:
require(data.table)
count=dcast(df,x+y~paste(value,"_count",sep=""))
weights=dcast(df,x+y~paste(value,"_sum_of_weights",sep=""),value.var = "weight",fun.aggregate = sum)
result=merge(count,weights,by=c("x","y"))
结果:
x y blue_count red_count blue_sum_of_weights red_sum_of_weights
10.0 1 1 1 1.00 1
10.0 10 1 0 0.50 0
3.0 8 3 1 2.75 4
3.4 5 1 0 2.00 0
尽管我不得不承认如果我们可以在 dcast 中使用两个函数会简单得多。据说你可以,但我一直收到错误... 经过一些挖掘后,我在这个线程 reshape2: multiple results of aggregation function? 中找到了一个非常好的答案,它为 dcast 定义了一个包装函数,如下所示:
dcastMult <- function(data, formula, value.var = "value",
funs = list("min" = min, "max" = max)) {
require(reshape2)
if (is.null(names(funs)) | any(names(funs) == "")) stop("funs must be named")
Form <- formula(formula)
LHS <- as.character(Form[[2]])
if (length(LHS) > 1) LHS <- LHS[-1]
temp <- lapply(seq_along(funs), function(Z) {
T1 <- dcast(data, Form, value.var = value.var,
fun.aggregate=match.fun(funs[[Z]]), fill = 0)
Names <- !names(T1) %in% LHS
names(T1)[Names] <- paste(names(T1)[Names], names(funs)[[Z]], sep = "_")
T1
})
Reduce(function(x, y) merge(x, y), temp)
}
使用这个可爱的函数,我们得到如下结果:
result=dcastMult(df,x+y~value,funs = list("count"=length,"sum_of_weights"=sum),value.var = "weight")
另一个选项:
df %>%
group_by(x, y, value) %>%
summarise(count = n(), sum = sum(weight)) %>%
gather(key, val, -(x:value)) %>%
unite(newkey, value, key) %>%
spread(newkey, val)
给出:
#Source: local data frame [4 x 6]
#Groups: x, y [4]
#
# x y blue_count blue_sum red_count red_sum
#* <dbl> <int> <dbl> <dbl> <dbl> <dbl>
#1 3.0 8 3 2.75 1 4
#2 3.4 5 1 2.00 NA NA
#3 10.0 1 1 1.00 1 1
#4 10.0 10 1 0.50 NA NA
这是一个使用 data.table::dcast
的简单解决方案:
require(data.table)
dcast(dt, x + y ~ value, value.var = "weight", fun.aggregate = list(length, sum))
# x y weight_length_blue weight_length_red weight_sum_blue weight_sum_red
# 1: 3.0 8 3 1 2.75 4
# 2: 3.4 5 1 0 2.00 0
# 3: 10.0 1 1 1 1.00 1
# 4: 10.0 10 1 0 0.50 0
其中,
dt = fread('x y value weight
10 1 red 1
3.4 5 blue 2
10 10 blue 0.5
3 8 blue 0.5
3 8 red 4
10 1 blue 1
3 8 blue 2
3 8 blue 0.25
')