簡體   English   中英

R data.table添加列作為另一個data.table的函數

[英]R data.table add column as function of another data.table

我有一個僅包含時間序列的數據表。 我有另一個包含兩列的數據表:start_time和end_time。 我想獲取第一個數據表並添加一列,該列的值是第二個數據表中所有行的計數,其中第一個數據表中的時間適合開始和結束時間。 這是我的代碼

start_date <- as.POSIXct(x = "2017-01-31 17:00:00", format = "%Y-%m-%d %H:%M:%S")
end_date <- as.POSIXct(x = "2017-02-01 09:00:00", format = "%Y-%m-%d %H:%M:%S")

all_dates <- as.data.table(seq(start_date, end_date, "min"))

colnames(all_dates) <- c("Bin")

start_times <- sample(seq(start_date,end_date,"min"), 100)
offsets <- sample(seq(60,7200,60), 100)
end_times <- start_times + offsets
input_data <- data.table(start_times, end_times)

這是我想做的,但這是錯誤的,並給出了錯誤。 寫這個的正確方法是什么?

all_dates[, BinCount := input_data[start_times < Bin & end_times > Bin, .N] ]

最后我應該得到類似

Bin                   BinCount
2017-01-31 17:00:00   1
2017-01-31 17:01:00   5
...

使用sqldf可以很容易地解決該問題,因為它提供了使用范圍檢查sqldf表的簡便方法。 因此,一種解決方案可能是:

The data from OP:
library(data.table)
start_date <- as.POSIXct(x = "2017-01-31 17:00:00", format = "%Y-%m-%d %H:%M:%S")
end_date <- as.POSIXct(x = "2017-02-01 09:00:00", format = "%Y-%m-%d %H:%M:%S")

all_dates <- as.data.table(seq(start_date, end_date, "min"))

colnames(all_dates) <- c("Bin")

start_times <- sample(seq(start_date,end_date,"min"), 100)
offsets <- sample(seq(60,7200,60), 100)
end_times <- start_times + offsets
input_data <- data.table(start_times, end_times)


library(sqldf)

result <- sqldf("SELECT all_dates.bin, count() as BinCount 
                FROM all_dates, input_data
                 WHERE all_dates.bin > input_data.start_times AND 
                 all_dates.bin < input_data.end_times
                 GROUP BY bin" )

result
                    Bin BinCount
1   2017-01-31 17:01:00        1
2   2017-01-31 17:02:00        1
3   2017-01-31 17:03:00        1
4   2017-01-31 17:04:00        1
5   2017-01-31 17:05:00        1
6   2017-01-31 17:06:00        1
...........
...........
497 2017-02-01 01:17:00        6
498 2017-02-01 01:18:00        5
499 2017-02-01 01:19:00        5
500 2017-02-01 01:20:00        4
 [ reached getOption("max.print") -- omitted 460 rows ]

data.table您要進行范圍data.table

library(data.table)

start_date <- as.POSIXct(x = "2017-01-31 17:00:00", format = "%Y-%m-%d %H:%M:%S")
end_date <- as.POSIXct(x = "2017-02-01 09:00:00", format = "%Y-%m-%d %H:%M:%S")

all_dates <- as.data.table(seq(start_date, end_date, "min"))

colnames(all_dates) <- c("Bin")

set.seed(123)
start_times <- sample(seq(start_date,end_date,"min"), 100)
offsets <- sample(seq(60,7200,60), 100)
end_times <- start_times + offsets
input_data <- data.table(start_times, end_times)

## doing the range-join and calculating the number of items per bin in one chained step
input_data[
    all_dates
    , on = .(start_times < Bin, end_times > Bin)
    , nomatch = 0
    , allow.cartesian = T
][, .N, by = start_times]

#             start_times N
# 1:  2017-01-31 17:01:00 1
# 2:  2017-01-31 17:02:00 1
# 3:  2017-01-31 17:03:00 1
# 4:  2017-01-31 17:04:00 1
# 5:  2017-01-31 17:05:00 1
# ---                      
# 956: 2017-02-01 08:56:00 6
# 957: 2017-02-01 08:57:00 4
# 958: 2017-02-01 08:58:00 4
# 959: 2017-02-01 08:59:00 5
# 960: 2017-02-01 09:00:00 5

注意:

  • 我已將all_dates對象放在all_dates的右側,因此即使它們是您的all_dates ,結果也包含input_data列的名稱(有關此主題的討論,請參閱此問題
  • 我使用set.seed() ,因為您正在采樣

不需要,但這是使用tidyverse的緊湊型替代解決方案。 使用lubridate解析器, interval%within%以及purrr::map_int生成所需的bin計數。

library(tidyverse)
library(lubridate)
start_date <- ymd_hms(x = "2017-01-31 17:00:00") # lubridate parsers
end_date <- ymd_hms(x = "2017-02-01 09:00:00")

all_dates <- tibble(seq(start_date, end_date, "min")) # tibble swap for data.table

colnames(all_dates) <- c("Bin")

start_times <- sample(seq(start_date,end_date,"min"), 100)
offsets <- sample(seq(60,7200,60), 100)
end_times <- start_times + offsets
input_data <- tibble(
  start_times,
  end_times,
  intvl = interval(start_times, end_times) # Add interval column
  )

all_dates %>% # Checks date in Bin and counts intervals it lies within
  mutate(BinCount = map_int(.$Bin, ~ sum(. %within% input_data$intvl)))
# A tibble: 961 x 2
   Bin                 BinCount
   <dttm>                 <int>
 1 2017-01-31 17:00:00        0
 2 2017-01-31 17:01:00        0
 3 2017-01-31 17:02:00        0
 4 2017-01-31 17:03:00        0
 5 2017-01-31 17:04:00        0
 6 2017-01-31 17:05:00        0
 7 2017-01-31 17:06:00        0
 8 2017-01-31 17:07:00        1
 9 2017-01-31 17:08:00        1
10 2017-01-31 17:09:00        1
# ... with 951 more rows

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM