-3

我对 data.table 的超快速度感到惊讶。下面的代码完全符合我的需要,但是当在大表上执行时,它的性能不是很好。

确信这可以通过 data.table 更快地完成,但我不知道如何。

输出

输出需要是一个矩阵,其中行名是一个规则的天序列。分别为每一列:

  • 第一个值之前的所有值都需要为 NA
  • 最后一个值之后的所有值都必须是 NA
  • 在第一个值和最后一个值之间需要添加 0,因为输入表中不存在

以下代码显示了结果的样子:

M <- 
  matrix(c(NA, NA, NA, 2, 0, 1, 3, 0, 2 , NA,
           NA, NA, 3,  1, 3, 2, 1, 2, NA, NA), 
           ncol = 2, 
           dimnames = list(as.character((Sys.Date() + 0:9)),
                           c("E1", "E2")))

输出示例

##            E1 E2
## 2017-01-27 NA NA
## 2017-01-28 NA NA
## 2017-01-29 NA  2
## 2017-01-30  2  2
## 2017-01-31  0  2
## 2017-02-01  3  1
## 2017-02-02  1  3
## 2017-02-03  0  3
## 2017-02-04  2 NA
## 2017-02-05 NA NA

输入

下表显示了编码/功能的来源/输入:

DS <- data.table(
  E = c(rep("E1", 4), rep("E2", 6)),
  C = c(c(Sys.Date() + c(3, 5, 6, 8)),
        c(Sys.Date() + c(2, 3, 4, 5, 6, 7))),
  S = round(runif(n = 10,min = 1, max = 3), 0),
  key = c("E", "C"))

##      E          C S
##  1: E1 2017-01-30 3
##  2: E1 2017-02-01 1
##  3: E1 2017-02-02 2
##  4: E1 2017-02-04 1
##  5: E2 2017-01-29 3
##  6: E2 2017-01-30 2
##  7: E2 2017-01-31 3
##  8: E2 2017-02-01 1
##  9: E2 2017-02-02 2
## 10: E2 2017-02-03 3

输入示例

代码工作

以下几行正是我需要的,而且很简单。不过效率不高。
真实表有 700 个唯一的 C 值和 200 万个 E 值。

# Create the regular time line per day
CL <- c(C= (Sys.Date() + 0:9))

# Determine first and last per E
DM <- DS[, .(MIN = min(C), MAX = max(C)), by =.(E)]

# Generate all combinations 
CJ <- CJ(E = DS$E, C = CL, unique = TRUE)

# Join 
DC <- DS[CJ, on = .(E, C)][!is.na(E)]

# replace NA by 0
DC[is.na(S), S:=0]

# Lead-in
DC[DM, on=.(E, C<MIN), S:=NA]

# Lead-out
DC[DM, on=.(E, C>MAX), S:=NA]

# Cast to matrix format
DC2 <- dcast(
  data = DC, formula = C ~ E, 
  fun.aggregate = sum, value.var = "S")

# coerce to matrix
M3 <- as.matrix(DC2[, -1])

# add row nanes
rownames(M3) <- format(CL, "%Y-%m-%d")

我做了一些冗长的、不可读的、笨拙的编码,它在 35 秒内创建了包含 1.2B 个单元的矩阵。使用 data.table 必须尽可能快但更优雅,但不是这样。

4

2 回答 2

1

A data.table,就像 adata.frame下面的一切都是一个列表(长度 = 列数)

2 亿列是很多列 - 这会使任何事情变慢。

转换为“宽”的描述会使具有大量NA值的数据膨胀。您几乎可以肯定地在“长格式”上执行所需的分析并使用键。

从您的问题中不清楚您需要什么,但您可以计算各种总和

# convert to an IDate
DT[, CALDAY := as.IDate(CALDAY)]
# get range of dates
rangeDays <- DT[,range(CALDAY)]

all_days <- as.IDate(seq(rangeDays[1],rangeDays[2], by=1)) 
# create sums
DT_sum <- DT[, list(VALUE= sum(VALUE)), keyby = list(ENTITY, CALDAY)]

然后使用实体和日期进行索引。

 DT_sum[.("2a8605e2-e283-11e6-a3bb-bbe3fd226f8d", all_days)]

如果你需要用 0 替换 NA

na_replace <- function(x,repl=0){x[is.na(x)]<-repl;x}

DT_sum[.("2a8605e2-e283-11e6-a3bb-bbe3fd226f8d", all_days), na_replace(VALUE)]
于 2017-01-24T22:57:12.947 回答
0

这可以解决问题。但是性能还是不好。
它以 DS 作为输入参数。结果是一个 data.table 应该通过以下方式强制转换为矩阵:

M <- as.matrix(build_timeseries_DT(DS))

功能

build_timeseries_DT <- function(DS){

  # regular time serie for complete range with index
  dtC <- data.table(
    CAL = seq(min(DS$C), max(DS$C), by = "day"))[, idx:= 1:.N]

  # add row index (idx) to sales
  DQ <- dtC[DS, on = "CAL"]
  setkey(DQ, "ENT")

  # calculate min index per ENT
  DM <- DQ[, .(MIN = min(idx), MAX = max(idx)), by = .(ENT)]

  # allocate memory, assign 0 and set rownames by reference
  DT <- dtC[, .(CAL)][, (DM[, ENT]):= 0L][, CAL:= NULL]
  setattr(DT, "row.names", format(dtC$CAL, "%Y-%m-%d"))

  # Set NA for the Lead-in and out, next populate values by ref
  for(j in colnames(DT)){
    set(x     = DT, 
        i     = c(1L:(DM[j, MIN]), (DM[j, MAX]):DT[, .N]), 
        j     = j, 
        value = NA )
    set(x     = DT, 
        i     = DQ[j, idx], 
        j     = j, 
        value = DQ[j, SLS] )}

  return(DT)
}

测试数据

DS <- data.table(
  ENT = c("A", "A", "A", "B", "B", "C", "C", "C", "D", "D"),
  CAL = c(Sys.Date() + c(0, 5, 6, 3, 8, 1, 2, 9, 3, 5)),
  SLS = as.integer(c(1, 2, 1, 2, 3, 1, 2, 3, 2, 1)),
  key = c("ENT", "CAL"))

   ENT        CAL SLS
 1:   A 2017-01-28   1
 2:   A 2017-02-02   2
 3:   A 2017-02-03   1
 4:   B 2017-01-31   2
 5:   B 2017-02-05   3
 6:   C 2017-01-29   1
 7:   C 2017-01-30   2
 8:   C 2017-02-06   3
 9:   D 2017-01-31   2
10:   D 2017-02-02   1  

结果

as.matrix(build_timeseries_DT(DS))

      A  B  C  D
 [1,]  1 NA NA NA
 [2,]  0 NA  1 NA
 [3,]  0 NA  2 NA
 [4,]  0  2  0  2
 [5,]  0  0  0  0
 [6,]  2  0  0  1
 [7,]  1  0  0 NA
 [8,] NA  0  0 NA
 [9,] NA  3  0 NA
[10,] NA NA  3 NA

结果与颜色

于 2017-01-28T20:37:58.507 回答