dcast中的自定义聚合函数

时间:2016-06-12 05:14:25

标签: r aggregation reshape2

我需要重新格式化表格。该表看起来像:

date   ItemID   NewPrice   Sale Amount
1-1     1         5            3
1-1     2         8            2
1-1     3         3            5
1-2     1         6            4
1-2     3         4            3
1-3     2         7            2
1-3     3         2            1

我要重新制定的第一个表格如下:

date   item_1    item_2    item_3
1-1      3         2         5 
1-2      4         0         3
1-3      0         2         1

项目ID成为列名称,值为销售额。棘手的部分是,有些日子里,某些项目没有记录,就像1-2中第2项没有项目记录一样。在这种情况下,销售金额应填写为0。

我想重新拟定的第二个表格如下:

date     item_1     item_2     item_3
1-1        5          8          3
1-2        6          8          4
1-3        6          7          2

所以我想要做的是使用item_id作为列,并使用NewPrice作为每个日期的值。

棘手的部分是,在每一天,总会有一些项目没有出现,所以当天没有NewPrice这个项目。在这种情况下,NewPrice应该是最后一天的NewPrice。

3 个答案:

答案 0 :(得分:3)

以下是第一部分的基础R解决方案:

xtabs(`Sale Amount` ~ date + ItemID, DF)
##      ItemID
## date  1 2 3
##   1-1 3 2 5
##   1-2 4 0 3
##   1-3 0 2 1

对于第二部分,我们在na.locf的动物园中使用tapply。如果第一个日期有NA,则na.rm = FALSE。在这种情况下,我们将其保留为NA。

library(zoo)

na.locf(tapply(DF$NewPrice, DF[c("date", "ItemID")], c), na.rm = FALSE)
##      ItemID
## date  1 2 3
##   1-1 5 8 3
##   1-2 6 8 4
##   1-3 6 7 2

注意:可重复形式的输入DF为:

Lines <- "date   ItemID   NewPrice   'Sale Amount'
1-1     1         5            3
1-1     2         8            2
1-1     3         3            5
1-2     1         6            4
1-2     3         4            3
1-3     2         7            2
1-3     3         2            1"
DF <- read.table(text = Lines, header = TRUE, check.names = FALSE)

答案 1 :(得分:2)

reshape2的后继者是tidyr,它与dplyr很好地整合。你的第一个案例非常简单:

library(dplyr)
library(tidyr)

       # get rid of excess column
df %>% select(-NewPrice) %>% 
    # fix labels so they'll make nice column names
    mutate(ItemID = paste0('item_', ItemID)) %>% 
    # spread from long to wide, filling with 0 instead of NA
    spread(ItemID, Sale.Amount, fill = 0)

#   date item_1 item_2 item_3
# 1  1-1      3      2      5
# 2  1-2      4      0      3
# 3  1-3      0      2      1

对于第二个,请明确使用fill代替spread中的参数:

       # get rid of excess column
df %>% select(-Sale.Amount) %>% 
    # fix labels so they'll make nice column names
    mutate(ItemID = paste0('item_', ItemID)) %>% 
    # spread from long to wide
    spread(ItemID, NewPrice) %>% 
    # fill NA values with previous value
    fill(-date)


#     date item_1 item_2 item_3
# 1    1-1      5      8      3
# 2    1-2      6      8      4
# 3    1-3      6      7      2

答案 2 :(得分:2)

使用dcast

可以在一行中轻松完成
library(data.table)
dcast(setDT(dfN), date~paste0("item_", ItemID), value.var="Sale.Amount", fill=0)
#   date item_1 item_2 item_3
#1:  1-1      3      2      5
#2:  1-2      4      0      3
#3:  1-3      0      2      1

对于第二种情况,我们可以使用na.locf将NA值替换为之前的非NA值(在使用dcast重新形成'wide'之后)。

library(zoo)
dcast(setDT(dfN), date~paste0("item_", ItemID), value.var="NewPrice")[, 
          (2:4) := lapply(.SD, na.locf), .SDcols = item_1:item_3][]
#   date item_1 item_2 item_3
#1:  1-1      5      8      3
#2:  1-2      6      8      4
#3:  1-3      6      7      2