【问题标题】:setDT, Error in x[j]: invalid subscript type 'list', when executed as part of a functionsetDT,x[j] 中的错误:作为函数的一部分执行时,下标类型“列表”无效
【发布时间】:2018-08-17 16:28:44
【问题描述】:

我有一些带有开始时间和结束时间的事件记录的数据框。 我想将记录扩展为多个具有一致时间间隔的记录,比如说一小时的间隔。 例如,假设数据框包含两条记录:

EventId   Day   StartTime   EndTime
1         Mon   1           3
2         Tues  2           5

我想要的新数据框应该是这样的

EventId   Day    Time
1         Mon    1
1         Mon    2
2         Tues   2
2         Tues   3
2         Tues   4

我的函数使用 data.table::setDT 来扩展记录,如下所示:

makeIncrementalRecords <- function(df) {
    new <- data.table::setDT(df)[,
                                 .(Time = seq(StartTime,
                                              EndTime,
                                              by = 1)),
                                 by = .(EventId, Day)]

逐行执行,我没有问题,我得到了我想要的结果。当我将函数作为加载包的一部分执行时,出现以下错误...

Error in x[j]: invalid subscript type 'list'

我完全不明白为什么这段代码在作为函数执行时会突然停止工作。我猜这与本地功能环境有关。当我在全局环境中将数据框创建为“df”并在控制台中执行 setDT 函数时,它可以工作。

有什么建议吗?

谢谢

【问题讨论】:

  • 是的,正如问题所述,我将其称为作为我创建的包的一部分的函数。如果代码直接在脚本中运行,但作为函数调用,我会收到错误消息。我正在加载 data.table 作为包的一部分。
  • 抱歉我的误读。也许你已经知道了,但是这里有一些关于在包中使用 data.table 的说明:stackoverflow.com/a/10529888
  • 谢谢弗兰克。这是一个很大的帮助。它突然通过向函数的 roxygen cmets 添加一个@import 来工作

标签: r data.table


【解决方案1】:

编辑

我认为这个结果就是你想要的。

structure(list(EventId = 1:2, Day = c("Mon", "Tues"), StartTime = 1:2, EndTime = c(3L, 5L)), 
          .Names = c("EventId", "Day", "StartTime", "EndTime"), 
          row.names = c(NA, -2L), class = "data.frame") -> test_df 


library(dplyr)
library(tidyr)

generate_val <- function(startT, endT){
  (seq(from = startT, to = (endT-1), by = 1))
}

test_df %>%
  rowwise() %>%
  do(new_vars = generate_val(.$StartTime, .$EndTime)) %>%
  bind_cols(test_df %>% select(-c(StartTime:EndTime))) %>%
  unnest()

# A tibble: 5 x 3
  EventId Day   new_vars
    <int> <chr>    <dbl>
1       1 Mon          1
2       1 Mon          2
3       2 Tues         2
4       2 Tues         3
5       2 Tues         4

要将其打包到函数中,您必须遵循此处描述的 NSE 过程 - Programming with dplyr


如果您不介意使用tidyr,这应该可以。对于大型数据集(行数 > 100 万),它可能比 data.table 慢一些。

library(tidyr)

test_df %>%
  gather(., key = Time_type, value = Time, -EventId, -Day)

  EventId  Day Time_type Time
1       1  Mon StartTime    1
2       2 Tues StartTime    2
3       1  Mon   EndTime    3
4       2 Tues   EndTime    5

【讨论】:

  • 这没有达到我正在寻找的格式。我需要每小时复制一次记录。因此,如果事件跨越 4 小时,例如,从 2 到 6,则需要有 4 条记录,1 代表每小时 2、3、4 和 5。
  • 我想你可以用 purrr 改变一个列表列,然后 unnest。
【解决方案2】:

这是一个类似于 cmets 中提出的解决方案。

library(tidyverse)

makeIncrementalRecords <- function(data){
    data %>% 
        mutate(Time = map2(StartTime, EndTime, ~seq(.x, .y-1))) %>% 
        unnest() %>% 
        select(EventId, Day, Time)
}

makeIncrementalRecords(df)
#   EventId Day    Time
# 1       1 Mon       1
# 2       1 Mon       2
# 3       2 Tues      2
# 4       2 Tues      3
# 5       2 Tues      4

或者如果你想保留它data.table

makeIncrementalRecords2 <- function(data){
    data.table::setDT(data)[, .(Time = seq(StartTime, EndTime-1, by = 1)), by = .(EventId, Day)]
}

makeIncrementalRecords2(df)
#    EventId  Day Time
# 1:       1  Mon    1
# 2:       1  Mon    2
# 3:       2 Tues    2
# 4:       2 Tues    3
# 5:       2 Tues    4

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-02-06
    • 2017-09-27
    • 2017-10-05
    • 1970-01-01
    • 2015-03-19
    • 2015-11-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多