Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/r/76.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
R 按元素组将每小时数据转换为每日和双日数据_R_Date_Dataframe_Bigdata - Fatal编程技术网

R 按元素组将每小时数据转换为每日和双日数据

R 按元素组将每小时数据转换为每日和双日数据,r,date,dataframe,bigdata,R,Date,Dataframe,Bigdata,我知道这个问题并不新鲜,但我的案例包含了一些以前的答复无法完全解决的特点 我在R中有一个非常大的数据帧,称为“df”(包括1400万个元素),格式如下: ID datetime measurem 1: 1459 2013-01-08 00:00:00 2.24 2: 1459 2013-01-08 01:00:00 2 3: 1459 2013-01-

我知道这个问题并不新鲜,但我的案例包含了一些以前的答复无法完全解决的特点

我在R中有一个非常大的数据帧,称为“df”(包括1400万个元素),格式如下:

            ID               datetime    measurem
     1:    1459   2013-01-08 00:00:00        2.24
     2:    1459   2013-01-08 01:00:00        2
     3:    1459   2013-01-08 02:00:00        2.54
     4:    1459   2013-01-08 03:00:00        3.98
     5:    1459   2013-01-08 04:00:00        2
     6:    1459   2013-01-08 05:00:00        2
     7:    1459   2013-01-08 06:00:00        3
             ....
  1007:    2434   2013-01-08 00:00:00        3.45
  1008:    2434   2013-01-08 01:00:00        3
  1009:    2434   2013-01-08 02:00:00        4
  1010:    2434   2013-01-08 03:00:00        5.01
  1011:    2434   2013-01-08 04:00:00        4
            ....
  3245:    4780   2013-01-10 00:00:00        3
  3246:    4780   2013-01-10 01:00:00        4.73
  3247:    4780   2013-01-10 02:00:00        3
df的结构如下所示:

类“data.table”和“data.frame”:14103024 obs。共有3个变量:
$ID:chr“1459”1459“。。。
$datetime:POSIXct,格式:“2013-01-08 00:00:00”“2013-01-08 01:00:00”。。。
$measurem:num 2.24 2.54…

我想先将能量数据“measurem”转换为每日,然后再转换为双日(一次测量到上午12点,另一次测量到下午12点),同时保留ID列和日期。由于完整的数据帧太大,我将非常感谢任何可以相对快速工作的建议


提前谢谢你

如果我理解正确,那么我猜您希望根据ID、日期和AM/PM总结“测量值””列,因为问题中没有样本数据,所以我自己制定了解决方案:

数据

 set.seed(1234)
df <- data.frame(ID=rep(1:5,4),datetime=c("2013-01-08 00:00:00", "2013-01-09 01:00:00", "2013-01-09 13:00:00", "2013-01-08 02:00:00", "2013-01-08 15:00:00",
                                         "2013-01-08 16:00:00", "2013-01-09 01:00:00", "2013-01-09 02:00:00", "2013-01-08 03:00:00", "2013-01-09 18:00:00",
                                         "2013-01-08 14:00:00", "2013-01-09 19:00:00", "2013-01-08 11:00:00", "2013-01-09 10:00:00", "2013-01-08 18:00:00",
                                         "2013-01-09 19:00:00", "2013-01-09 03:00:00", "2013-01-09 02:00:00", "2013-01-09 21:00:00",
                                         "2013-01-09 11:00:00"),measurement=abs(rnorm(20)))
datetime <- as.POSIXlt(df$datetime)
date <- as.Date(datetime)
ind <- ifelse(datetime$hour >= 12,"PM","AM")
df$ind <- ind
df$date <- date
set.seed(1234)

df如果我理解正确,那么我猜您希望根据ID、日期和AM/PM总结“测量值””列,因为问题中没有样本数据,我已经制定了自己的解决方案:

数据

 set.seed(1234)
df <- data.frame(ID=rep(1:5,4),datetime=c("2013-01-08 00:00:00", "2013-01-09 01:00:00", "2013-01-09 13:00:00", "2013-01-08 02:00:00", "2013-01-08 15:00:00",
                                         "2013-01-08 16:00:00", "2013-01-09 01:00:00", "2013-01-09 02:00:00", "2013-01-08 03:00:00", "2013-01-09 18:00:00",
                                         "2013-01-08 14:00:00", "2013-01-09 19:00:00", "2013-01-08 11:00:00", "2013-01-09 10:00:00", "2013-01-08 18:00:00",
                                         "2013-01-09 19:00:00", "2013-01-09 03:00:00", "2013-01-09 02:00:00", "2013-01-09 21:00:00",
                                         "2013-01-09 11:00:00"),measurement=abs(rnorm(20)))
datetime <- as.POSIXlt(df$datetime)
date <- as.Date(datetime)
ind <- ifelse(datetime$hour >= 12,"PM","AM")
df$ind <- ind
df$date <- date
set.seed(1234)
dfOP已要求提供任何建议,因为生产数据集包含1400万行,因此可以相对快速地工作

不幸的是,被接受的答案在速度和内存消耗方面相当低效:

  • 它创建了许多辅助向量,这些辅助向量作为新列添加到
    df
    ,因此被存储两次
  • df的每次更新都会复制整个对象
  • data.table
    解决方案不使用
    data.table
    语法来避免复制操作
  • POSIXlt
    需要52个字节来存储一个日期时间实例,而
    POSIXct
    只需要8个字节
我建议使用
数据。表

# create sample data, see function definition below
df <- create_sample_data(n_id = 4L, n_hr = 24L * 2L)
str(df)
资料 即使是中等规模的问题,基本R解决方案也比
data.table
版本慢很多。PKumar的
data.table
解决方案中效率低下的数据操作增加了50%的性能损失。此外,不必要地分配了56 MB的额外内存,而
df
onyl需要17 MB。

由于生产数据集包含1400万行,OP已请求提供任何可以相对快速工作的建议

不幸的是,被接受的答案在速度和内存消耗方面相当低效:

  • 它创建了许多辅助向量,这些辅助向量作为新列添加到
    df
    ,因此被存储两次
  • df的每次更新都会复制整个对象
  • data.table
    解决方案不使用
    data.table
    语法来避免复制操作
  • POSIXlt
    需要52个字节来存储一个日期时间实例,而
    POSIXct
    只需要8个字节
我建议使用
数据。表

# create sample data, see function definition below
df <- create_sample_data(n_id = 4L, n_hr = 24L * 2L)
str(df)
资料
即使是中等规模的问题,基本R解决方案也比
data.table
版本慢很多。PKumar的
data.table
解决方案中效率低下的数据操作增加了50%的性能损失。此外,56 MB的额外内存被不必要地分配,而
df
onyl需要17 MB。

因此,您试图
ID
datetime
上聚合
?你有每天和每个ID的每小时数据吗?@jwells是的,我想对每个ID进行转换。我有很多年的每小时数据,但不是所有ID都有这段时间的数据。所以我100%肯定有更好的方法使用
apply
,我现在还不太擅长,在没有真正看到数据的情况下很难确定,但我会尝试:
newmeas谢谢。它给出了每个ID都有数据的整个期间的总和。我怎么能把它转换成每日总和呢?(我想)
~ID+datetime
,所以你试图对
ID
datetime
进行
聚合?你有每天和每个ID的每小时数据吗?@jwells是的,我想对每个ID进行转换。我有很多年的每小时数据,但不是所有ID都有这段时间的数据。所以我100%肯定有更好的方法使用
apply
,我现在还不太擅长,在没有真正看到数据的情况下很难确定,但我会尝试:
newmeas谢谢。它给出了每个ID都有数据的整个期间的总和。我怎样才能将其转换为每日金额?(我想)
~ID+datetime
library(data.table)
# daily aggregates
setDT(df)[, .(sum_measurem = sum(measurem)), 
          by = .(ID, date = as.IDate(datetime))]
       ID       date sum_measurem
1: 000001 2013-01-08     18.01187
2: 000001 2013-01-09     22.53423
3: 000002 2013-01-08     21.77239
4: 000002 2013-01-09     15.57561
5: 000003 2013-01-08     14.79938
6: 000003 2013-01-09     20.09797
7: 000004 2013-01-08     15.21066
8: 000004 2013-01-09     25.47120
# bi-daily aggregates
setDT(df)[, .(sum_measurem = sum(measurem)), 
          by = .(ID, date = as.IDate(datetime), AM = hour(datetime) <= 12L)]
        ID       date    AM sum_measurem
 1: 000001 2013-01-08  TRUE    10.677509
 2: 000001 2013-01-08 FALSE     7.334362
 3: 000001 2013-01-09  TRUE    12.456765
 4: 000001 2013-01-09 FALSE    10.077470
 5: 000002 2013-01-08  TRUE    12.099480
 6: 000002 2013-01-08 FALSE     9.672908
 7: 000002 2013-01-09  TRUE     8.672189
 8: 000002 2013-01-09 FALSE     6.903426
 9: 000003 2013-01-08  TRUE     8.976965
10: 000003 2013-01-08 FALSE     5.822411
11: 000003 2013-01-09  TRUE    11.131718
12: 000003 2013-01-09 FALSE     8.966252
13: 000004 2013-01-08  TRUE     8.413315
14: 000004 2013-01-08 FALSE     6.797342
15: 000004 2013-01-09  TRUE    15.111185
16: 000004 2013-01-09 FALSE    10.360017
create_sample_data <- function(n_id, n_hr) {
  set.seed(1234L)
  data.frame(
    ID = rep(sprintf("%06i", seq_len(n_id)), each = n_hr),
    datetime = rep(seq(as.POSIXct("2013-01-08"), length.out = n_hr, by = "1 hour"), n_id),
    measurem = abs(rnorm(n_id * n_hr)),
    stringsAsFactors = FALSE
    )
}
df0 <- create_sample_data(n_id = 100L, n_hr = 24L * 365L)

microbenchmark::microbenchmark(
  copy = df <- copy(df0),
  uwe_dt = {
    df <- copy(df0)
    setDT(df)[, .(sum_measurem = sum(measurem)), 
              by = .(ID, date = as.IDate(datetime), AM = hour(datetime) < 12L)]
  },
  PKumar_dt = {
    df <- copy(df0)
    datetime <- as.POSIXlt(df$datetime)
    date <- as.Date(datetime)
    ind <- ifelse(datetime$hour >= 12,"PM","AM")
    df$ind <- ind
    df$date <- date
    dt <- setDT(df)
    dt[,list(sum_measure = sum(measurem)),by=list(ID,date,ind)]
  },
  PKumar_baseR = {
    df <- copy(df0)
    datetime <- as.POSIXlt(df$datetime)
    date <- as.Date(datetime)
    ind <- ifelse(datetime$hour >= 12,"PM","AM")
    df$ind <- ind
    df$date <- date
    fin <- aggregate(measurem ~ ID + date + ind, data = df, sum)
    fin[order(fin$ID),]
  },
  times = 11L
)
Unit: milliseconds
         expr        min          lq        mean      median          uq         max neval
         copy    3.94761    4.391457    5.169909    5.537982    5.864401    5.997876    11
       uwe_dt  271.89460  301.001006  339.913084  312.151541  344.251971  540.018306    11
    PKumar_dt  417.57141  464.778485  575.547756  475.562955  689.848696  851.180584    11
 PKumar_baseR 6356.93567 6707.847607 6896.174857 6863.069477 6903.442520 8112.316770    11