我有4190145次观察。我想把我的约会时间改为月末。我在下面解释。
以下是我的数据部分:
Time1
2015/01/15
2015/02/24
2015/07/18
2015/11/10
2016/02/20
2016/04/26
2016/08/17
我想创建新列Time2
:
Time1 Time2
2015/01/15 2015/01/31
2015/02/24 2015/02/28
2015/07/18 2015/07/31
2015/11/10 2015/11/30
2016/02/20 2016/02/29
2016/04/26 2016/04/30
2016/08/17 2016/08/31
代码是:
data[, Time2 := Time1]
day(data$Time2) <- days_in_month(data$Time1)
然而,我收到了错误。
Error: cannot allocate vector of size N Mb
因此,我在Stack Overflow上搜索我的问题并找到this。
我使用gc()
但仍无效。所以我看到了sessionInfo()
:
sessionInfo()
R version 3.3.3 (2017-03-06)
Platform: i386-w64-mingw32/i386 (32-bit)
Running under: Windows 7 (build 7601) Service Pack 1
attached base packages:
[1] stats graphics grDevices utils datasets methods base
other attached packages:
[1] lubridate_1.6.0 data.table_1.10.4
loaded via a namespace (and not attached):
[1] lazyeval_0.2.0 R6_2.2.0 assertthat_0.1 magrittr_1.5 DBI_0.5-1 tools_3.3.3 dplyr_0.5.0 tibble_1.2
[9] Rcpp_0.12.9 stringi_1.1.2 stringr_1.1.0
我认为这是因为我的电脑只是32位。并且memory.limit()
可以将大小设置为4000,因为我的RAM是4 GB。
此外,我发现如果我使用data.table
执行,我可以运行。
所以,我的问题是如何将我的代码从day(data$Time2) <- days_in_month(data$Time1)
更改为data.table
格式。
也许喜欢data[, day(data$Time2) := days_in_month(data$Time1)]
?
我知道这是不正确的,因为我得到了
错误:无法在同一查询中两次分配到同一列 (检测到重复)。
有什么建议吗?
答案 0 :(得分:2)
也许这有用吗?
set.seed(120340)
NN = 5e6
DT = data.table(Time1 =
sprintf('%04d/%02d/%02d',
sample(2000:2017, NN, TRUE),
sample(12, NN, TRUE),
sample(28, NN, TRUE)))
# potential memory bottleneck
DT[ , c('y', 'm', 'd') := tstrsplit(Time1, '/')]
days_month = data.table(
month = sprintf('%02d', 1:12),
days = c(31L, 28L, 31L, 30L, 31L, 30L,
31L, 31L, 30L, 31L, 30L, 31L)
)
DT[days_month, d_end := i.days, on = c(m = 'month')]
DT[m == 2L & as.integer(y) %% 4L == 0L, d_end := 29L]
DT[ , Time2 := do.call(paste, c(.SD, list(sep = '/'))),
.SDcols = c('y', 'm', 'd_end')]
如果失败了,我猜这会减少对内存的影响:
DT[ , y := gsub('/.*', '', Time1)]
DT[ , c('m', 'd') := tstrsplit(Time1, '/')[2L:3L], by = y]
如果失败了,我建议购买更多RAM,或者在部署到更严重的机器之前使用一部分数据。另外,正如Frank指出的那样,你真的希望将它们存储为IDates
以获得最大的内存效率。
答案 1 :(得分:0)
为了完整起见,我将使用<img class="anim-object bluebag iteration-1 speed-7 " src="http://via.placeholder.com/350x150" />
和data.table
执行此操作:
lubridate
# create sample data
library(data.table)
set.seed(120340)
NN <- 1e6
DT <- data.table(Time1 = sprintf('%04d/%02d/%02d',
sample(2000:2017, NN, TRUE),
sample(12, NN, TRUE),
sample(28, NN, TRUE)))
ceiling_date()
library(lubridate) DT[, Time2 := ceiling_date(ymd(Time1), "month") - 1] DT
Time1 Time2
1: 2005/04/14 2005-04-30
2: 2007/01/11 2007-01-31
3: 2014/09/08 2014-09-30
4: 2017/05/13 2017-05-31
5: 2008/05/23 2008-05-31
---
999996: 2003/06/08 2003-06-30
999997: 2004/04/12 2004-04-30
999998: 2009/06/10 2009-06-30
999999: 2013/02/04 2013-02-28
1000000: 2014/03/05 2014-03-31
tables()
使用 NAME NROW NCOL MB COLS KEY
[1,] DT 1,000,000 2 16 Time1,Time2
Total: 16MB
的赋值运算符data.table
通过引用更新:=
,即不复制整个数据对象。
DT
获取一个日期时间对象,并将其四舍五入到指定时间单位的最近边界,即到下个月的第一天。因此,我们必须减去1天才能得到实际月份的最后一天。
ceiling_date()
as.IDate()
有自己的日期和时间类,带有整数存储空间,可用于快速排序和分组。在某些系统上,整数存储data.table
需要的内存少于may
:
double
DT[, Time1 := as.IDate(Time1, "%Y/%m/%d")] DT[, Time2 := as.IDate(ceiling_date(ymd(Time1), "month") - 1)] tables()
这里只需要一半的内存。