我有一个如下所示的数据框:
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",并且这些列是"权重" s的总和,用于"值"的每个不同值。如果可能的话,我也 喜欢为" 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个小时来完成600k行的前15%数据集,这不是很实用!但我确定必须有办法用现有的功能来做到这一点吗?
非常感谢您的任何帮助!
答案 0 :(得分:2)
您可以使用dplyr
和reshape2
功能组合执行此操作。首先,按x
,y
和value
分组(我们将后者的名称更改为color
,以避免在融化后重复列名称),然后计算计数和每个小组的总和。然后melt
结果将新计算的摘要放入" long"格式。最后,dcast
以获得广泛的"你要的格式。
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
答案 1 :(得分:2)
另一种选择:
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
答案 2 :(得分:1)
以下是使用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
')
答案 3 :(得分:0)
数据表的另一种方法:
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")