使用sum + product

时间:2016-07-21 15:00:53

标签: r casting aggregation reshape reshape2

我有一个如下所示的数据框:

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%数据集,这不是很实用!但我确定必须有办法用现有的功能来做到这一点吗?

非常感谢您的任何帮助!

4 个答案:

答案 0 :(得分:2)

您可以使用dplyrreshape2功能组合执行此操作。首先,按xyvalue分组(我们将后者的名称更改为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")