使用R将条件值填充到数据表中的特定行中

时间:2017-08-02 17:15:19

标签: r data.table

我有一张表格如下: DF

KEY    CAT      DATE   AMOUNT     VAR            VALUE
1      26    2015/10/1  1400 Event.Budget_Cat26   NA
1      26    2015/10/1  300  Event.Budget_Cat26   NA
1      26    2015/10/1  NA        NA              NA
1      22    2015/10/1  100  Event.Budget_Cat22   NA
1      22    2015/10/1  300  Event.Budget_Cat22   NA
1      22    2015/10/1  NA        NA              NA
2      21    2014/1/1   200  Event.Budget_Cat21   NA
2      21    2014/1/1   NA        NA              NA

这只是大表的一部分。基本上,每一行都是唯一的(KEY,CAT,DATE)。我想找到一种基于唯一标识来计算金额总和的方法,并将最终总和放入VALUE列。 另外,给VAR命名。 AMOUNT列仅存在于VALUE列中,我将最后删除整列,因此将其保留为NA即可。

最终结果将是

KEY    CAT      DATE   AMOUNT     VAR                 VALUE
1      26    2015/10/1  1400 Event.Budget_Cat26        NA
1      26    2015/10/1  300  Event.Budget_Cat26        NA
1      26    2015/10/1  NA   Scalar.Budget_Cat26_Amt  1700
1      22    2015/10/1  100  Event.Budget_Cat22        NA
1      22    2015/10/1  300  Event.Budget_Cat22        NA
1      22    2015/10/1  NA   Scalar.Budget_Cat22_Amt   400
2      21    2014/1/1   200  Event.Budget_Cat21        NA
2      21    2014/1/1   NA   Scalar.Budget_Cat21_Amt   200

我试过rbind和lapply,但结果不是我想要的

df[, 4:6 := lapply(.SD, 
       function(x) replace(x, is.na(x), c("",paste("Scalar_Budget_Cat",CAT,"_Amt",sep =""),sum(x, na.rm=TRUE))), 
             KEY, .SDcols=4]

有没有人可以帮我找出一个快速的方法来运行整个数据表,其中包含2,600,000行?谢谢

3 个答案:

答案 0 :(得分:1)

根据“KEY”,“CAT”,“DATE”进行分组后,有多种方法可以使用sum'AMOUNT'创建'VALUE',然后根据是否将这些值更改为NA它不是组的最后一个值。我们使用rep为'VALUE'列创建NAsum'AMOUNT',并修改'VAR'列以获得每个组的最后一个元素,而不是这样做使用`Scalar'子串

setDT(df1)[, c("VAR", "VALUE") := .(c(VAR[-.N], paste0("Scalar.", 
  sub("^[^.]+\\.", "", VAR[1]), "_Amt")), rep(c(NA, sum(AMOUNT, na.rm = TRUE)),
          c(.N-1, 1))), .(KEY, CAT, DATE)]
df1
#   KEY CAT      DATE AMOUNT                     VAR VALUE
#1:   1  26 2015/10/1   1400      Event.Budget_Cat26    NA
#2:   1  26 2015/10/1    300      Event.Budget_Cat26    NA
#3:   1  26 2015/10/1     NA Scalar.Budget_Cat26_Amt  1700
#4:   1  22 2015/10/1    100      Event.Budget_Cat22    NA
#5:   1  22 2015/10/1    300      Event.Budget_Cat22    NA
#6:   1  22 2015/10/1     NA Scalar.Budget_Cat22_Amt   400
#7:   2  21  2014/1/1    200      Event.Budget_Cat21    NA
#8:   2  21  2014/1/1     NA Scalar.Budget_Cat21_Amt   200

答案 1 :(得分:1)

我在260万行上尝试过,它真的很快。我们将任务拆分为两个操作。第一个是按KEYCATDATE对行进行分组,然后对AMOUNT列求和。之后,我们选择is.na(VAR) == T的行,并用相应的字符串填充VAR列。

df[, VALUE:=sum(AMOUNT, na.rm = T),by=list(KEY, CAT, DATE)][is.na(VAR), VAR:=paste0("Scalar_Budget_Cat",CAT,"_Amt"),]

与所需输出的差异在于NA中不再有VALUE个值。但是之后可以使用df[!is.na(AMOUNT), VALUE:=NA,]

进行设置

答案 2 :(得分:0)

以下是tidyverse的解决方案:

library(tidyverse)

KEY <- c(1, 1, 1, 1, 1, 1, 2, 2)
CAT <- c(26, 26, 26, 22, 22, 22, 21,21)
DATE <- c('2015/10/1', '2015/10/1', '2015/10/1', '2015/10/1', '2015/10/1', '2015/10/1', '2014/1/1', '2014/1/1')
AMOUNT <- c(1400, 300, NA, 100, 300, NA, 200, NA)
VAR <- c('Event.Budget_Cat26', 'Event.Budget_Cat26', NA, 'Event.Budget_Cat22', 'Event.Budget_Cat22', NA, 'Event.Budget_Cat21', NA)

df <- data_frame(KEY, CAT, DATE, AMOUNT, VAR, VALUE = NA)

summary_rows <- df %>%
  group_by(KEY, CAT, DATE) %>%
  summarise(VAR = paste0('Scalar.Budget_Cat', max(CAT), '_Amt'),
            VALUE = sum(AMOUNT, na.rm = T),
            AMOUNT = NA) %>%
  select(KEY, CAT, DATE, AMOUNT, VAR, VALUE) %>%
  arrange(KEY, -CAT, DATE)

df[is.na(AMOUNT),] <- summary_rows

df

##     KEY   CAT      DATE AMOUNT                     VAR VALUE
##   <dbl> <dbl>     <chr>  <dbl>                   <chr> <dbl>
## 1     1    26 2015/10/1   1400      Event.Budget_Cat26    NA
## 2     1    26 2015/10/1    300      Event.Budget_Cat26    NA
## 3     1    26 2015/10/1     NA Scalar.Budget_Cat26_Amt  1700
## 4     1    22 2015/10/1    100      Event.Budget_Cat22    NA
## 5     1    22 2015/10/1    300      Event.Budget_Cat22    NA
## 6     1    22 2015/10/1     NA Scalar.Budget_Cat22_Amt   400
## 7     2    21  2014/1/1    200      Event.Budget_Cat21    NA
## 8     2    21  2014/1/1     NA Scalar.Budget_Cat21_Amt   200