在每个组的日期范围末尾删除零

时间:2018-09-01 21:46:36

标签: r data.table

我的data.table看起来像这样:

+------------+--------+
|    Date    | CC  RR |
+------------+--------+
| 31.01.1985 | C1  0.1|
| 28.02.1985 | C1  0.8|
| 29.03.1985 | C1  0.9|
| 30.04.1985 | C1  2  |
| 31.05.1985 | C1  0  |
| 28.06.1985 | C1  0  |
| 31.01.1985 | C2  NA |
| 28.02.1985 | C2  0  |
| 29.03.1985 | C2  0.1|
| 30.04.1985 | C2  0  |
| 31.05.1985 | C2  0.4|
| 28.06.1985 | C2  0  |

CC(“公司代码”列)列具有用于标识公司的唯一公司代码,Date列具有日期,而RR列具有股票收益。我的实际数据集有超过2000家公司,为期30年。

我的问题如下:对于每个公司,我想将每个公司最后一行中RR的值从零转换为NA。具体来说,我想将以下行的RR的值从0更改为NA:

  • 31.05.1985 | c1
  • 28.06.1985 | c1
  • 28.06.1985 | c2

我不想更改中间日期,例如28.02.1985 | c230.04.1985 c2,并且我希望保留现有的NA,例如31.01.1985 | C2

我尝试使用

length(Data[, CC])-match(unique(Data[,CC]),rev(Test3[,CC]))+1

以获得各自公司代码最后一次出现的索引列表,然后迭代直到RR列中的第一个非零值,但是我不知道如何将其应用于r。中的data.table。

我当然可以转换所有零,但这不能解决我的问题:

Date[RR==0, "RR"] <- NA

有人可以帮我吗?我将不胜感激任何帮助。此致。

2 个答案:

答案 0 :(得分:3)

首先,请发布实际可用数据,而不要发布ascii艺术。我迅速将您发布的内容编辑到一个用空格分隔的文件中,并阅读:

R> dt <- fread("/tmp/data.txt")
R> dt
          Date CC  RR
 1: 31.01.1985 C1 0.1
 2: 28.02.1985 C1 0.8
 3: 29.03.1985 C1 0.9
 4: 30.04.1985 C1 2.0
 5: 31.05.1985 C1 0.0
 6: 28.06.1985 C1 0.0
 7: 31.01.1985 C2  NA
 8: 28.02.1985 C2 0.0
 9: 29.03.1985 C2 0.1
10: 30.04.1985 C2 0.0
11: 31.05.1985 C2 0.4
12: 28.06.1985 C2 0.0
R> dput(dt)
structure(list(Date = c("31.01.1985", "28.02.1985", "29.03.1985", 
"30.04.1985", "31.05.1985", "28.06.1985", "31.01.1985", "28.02.1985", 
"29.03.1985", "30.04.1985", "31.05.1985", "28.06.1985"), CC = c("C1", 
"C1", "C1", "C1", "C1", "C1", "C2", "C2", "C2", "C2", "C2", "C2"
), RR = c(0.1, 0.8, 0.9, 2, 0, 0, NA, 0, 0.1, 0, 0.4, 0)), row.names = c(NA, 
-12L), class = c("data.table", "data.frame"), 
.internal.selfref = <pointer: 0x5601c8da9cd0>)
R> 

dput()的输出可以由R评估并重新创建数据结构。

接下来,您的数据分析。首先,您想按小组工作! data.table的强项之一是分组。其次,您可能想要类似“零时的最大订单索引”之类的东西。以下应该起作用:

R> dt[, rle:=rleid(RR), by="CC"]
R> dt
          Date CC  RR rle
 1: 31.01.1985 C1 0.1   1
 2: 28.02.1985 C1 0.8   2
 3: 29.03.1985 C1 0.9   3
 4: 30.04.1985 C1 2.0   4
 5: 31.05.1985 C1 0.0   5
 6: 28.06.1985 C1 0.0   5
 7: 31.01.1985 C2  NA   1
 8: 28.02.1985 C2 0.0   2
 9: 29.03.1985 C2 0.1   3
10: 30.04.1985 C2 0.0   4
11: 31.05.1985 C2 0.4   5
12: 28.06.1985 C2 0.0   6
R> 

我们使用data.table中非常有用的rleid()函数来获取rle()重复的 index 值。现在,我们“只是”需要再次分组,如果rle的值等于max(rle)的值,我们便有了所需的位置并将其设置为NA

R> dt[, ind:=which.max(rle), by=CC]                # find max index
R> dt[ ind==rle & RR==0.0, RR:=NA_real_, by=CC ]   # at max ind AND zero set NA
R> dt[, ind:=NULL ]                                # remove index helper
R> dt
          Date CC  RR rle
 1: 31.01.1985 C1 0.1   1
 2: 28.02.1985 C1 0.8   2
 3: 29.03.1985 C1 0.9   3
 4: 30.04.1985 C1 2.0   4
 5: 31.05.1985 C1  NA   5
 6: 28.06.1985 C1  NA   5
 7: 31.01.1985 C2  NA   1
 8: 28.02.1985 C2 0.0   2
 9: 29.03.1985 C2 0.1   3
10: 30.04.1985 C2 0.0   4
11: 31.05.1985 C2 0.4   5
12: 28.06.1985 C2  NA   6
R> 

仅使用代码:

dt <- fread("/tmp/data.txt")
dt[, rle:=rleid(RR), by=CC]
dt[, ind:=which.max(rle), by=CC]
dt[ ind==rle & RR==0.0, RR:=NA_real_, by=CC ]
dt[, ind:=NULL ]
dt

答案 1 :(得分:2)

使用data.table的一种方法:

将日期从旧到新排序,然后创建累积总和rr。然后,所有行的总和为0,我们将rr更改为NA。请注意,由于cumsum没有一个na.rm arg,因此有几个额外的步骤。

# create example data
df <- data.frame(
    date = rep(seq(as.Date("1985-01-31"), by="day", length.out=6), 2),
    cc   = rep(c("c1", "c2"), each=6),
    rr   = c(0.1, 0.8, 0.9, 2, 0, 0, NA, 0, 0.1, 0, 0.4, 0),
    stringsAsFactors = FALSE
)

# change to data.table
library(data.table)
setDT(df)

# sort date old to new
df <- df[order(cc, -date)]

# save a copy of the rr col
df[ , rr_orig := rr]

# turn NAs into 0s because no "na.rm" arg in cumsum
df[is.na(rr), rr := 0]

# create cumsum
df[ , cumrr := cumsum(rr), by=cc]

# replace 0s with NAs in rr, wherever cumsum is 0
df[cumrr == 0, rr := NA]

# put the NAs back into rr from rr_orig
df[is.na(rr_orig), rr := NA]

# clean up by deleting rr_orig and cumrr cols, and re-sort date
df[ , c("rr_orig", "cumrr") := NULL]
df <- df[order(cc, date)]

结果

> df
          date cc  rr
 1: 1985-01-31 c1 0.1
 2: 1985-02-01 c1 0.8
 3: 1985-02-02 c1 0.9
 4: 1985-02-03 c1 2.0
 5: 1985-02-04 c1  NA
 6: 1985-02-05 c1  NA
 7: 1985-01-31 c2  NA
 8: 1985-02-01 c2 0.0
 9: 1985-02-02 c2 0.1
10: 1985-02-03 c2 0.0
11: 1985-02-04 c2 0.4
12: 1985-02-05 c2  NA