【问题标题】:Different results from dplyr and data.tabledplyr 和 data.table 的不同结果
【发布时间】:2023-04-05 00:17:01
【问题描述】:

可重现的数据集:

library(data.table)
library(dplyr)
library(zoo)

df = expand.grid(ID = sample(LETTERS[1:5]),
                 Date = seq.Date(as.Date("2012-01-01"), as.Date("2012-12-01"), by = "1 month"))
df = df[order(as.character(df$ID)),]
df = data.table(df, V1 = runif(nrow(df),0,1), V2 = runif(nrow(df),0,1), V3 = runif(nrow(df),0,1))

ind = sample(nrow(df), nrow(df)*.5)
na.gen <- function(x, ind){x[ind] <- NA}
df1 <- df %>% slice(., ind) %>% mutate_each(funs(na.gen), starts_with("V"))
df2 = df[!ind]
df <- rbind(df1, df2)
df <- df[order(as.character(df$ID), df$Date),]
df$ID = as.character(df$ID)

在上述数据集中,我的想法是使用 Last Observation Carried Forward 方法估算数据。我最初的问题是一个非常大的数据集,所以我测试了dplyrdata.table 解决方案。

final_dplyr <- df %>% group_by(ID) %>% mutate_each(funs(na.locf), starts_with("V"))
final_data.table <- df[, na.locf(.SD), by = ID]

data.table 给了我正确的解决方案,但是,dplyr 弄乱了从 NA 开始的子集。我使用dplyr 收到以下警告:

Warning messages:
1: In `[.data.table`(`_dt`, , `:=`(V1, na.locf(V1)), by = `_vars`) :
  Supplied 11 items to be assigned to group 1 of size 12 in column 'V1' (recycled leaving remainder of 1 items).

有人能帮我理解dplyr 做错了什么吗?

【问题讨论】:

  • 您写这些的方式非常不同。 na.locf(.SD) 对数据集进行操作,而 mutate_each 对每一列独立操作...
  • 但是,据我所知,na.locf 应该对列向量或数据框执行相同的插补。我最初为我的问题编写了dplyr 版本,但是当它不起作用时,我不得不编写data.table 版本,这让我感到惊讶。现在我不清楚,为什么一个有效,而另一个无效。

标签: r data.table dplyr


【解决方案1】:

好的,这里发生了很多事情。首先正如@Frank 所指出的,这两个命令对不同的对象进行操作。 na.locf(.SD) 在每个 ID 的子集数据表上,其中 dplyr 分别在每个 ID 的每一列上。

为了确定问题出在哪里,我将使用 data.table 等效于您的 dplyr 语法。

df[, lapply(.SD, na.locf), by=ID]
# warning

我们收到相同的警告信息。对于 1 个或多个组,每列返回的行数似乎不同。让我们检查一下。

df[, lapply(.SD, function(x) length(na.locf(x))), by=ID]
#    ID Date V1 V2 V3
# 1:  A   12 12 12 12
# 2:  B   12 12 12 12
# 3:  C   12 11 11 11 # <~~~ we've a winner!
# 4:  D   12 12 12 12
# 5:  E   12 12 12 12

为什么会这样?

head(df[ID == "C"])
#    ID       Date        V1        V2        V3
# 1:  C 2012-01-01        NA        NA        NA
# 2:  C 2012-02-01 0.7475075 0.8917311 0.7601174
# 3:  C 2012-03-01 0.4922747 0.7749479 0.3995417
# 4:  C 2012-04-01 0.9013631 0.3388313 0.8873779
# 5:  C 2012-05-01        NA        NA        NA
# 6:  C 2012-06-01        NA        NA        NA

nrow(df[ID == "C", na.locf(.SD), .SDcols= -c("ID")])
# 12 as expected

nrow(df[ID == "C", lapply(.SD, na.locf), .SDcols= -c("ID")])
# 12, but with warnings

在列上单独使用 na.locf() 会为 V1:V4 返回 11。为什么?好像是因为开头的NA?na.locf 有一个 na.rm 参数,默认设置为 TRUE,它从一开始就删除了 NA。所以让我们把它设置为false,然后再试一次

nrow(df[ID == "C", lapply(.SD, na.locf, na.rm=FALSE), .SDcols = -c("ID")])
# 12, no warnings

它与na.locf(.SD) 一起工作,因为它还在Date 列上运行na.locf,它返回12 行,我想。

本质上,您需要以某种方式在dplyr 中设置na.rm=FALSE,或者让dplyr 以某种方式处理整个对象。我也不知道该怎么做。

PS:请注意,您可以使用:= 通过引用来更新 data.table,而不是使用 data.table 语法返回新对象。

【讨论】:

  • 关于在 dplyr 中做什么,这似乎工作df %&gt;% group_by(ID) %&gt;% mutate_each(funs(na.locf(., na.rm=FALSE)), starts_with("V"))
  • 另一件似乎有效的事情:df %&gt;% group_by(ID) %&gt;% do(na.locf(. %&gt;% select(starts_with("V"))))(不是说这些应该添加到答案中,因为我不确定它们是否有效......哦,似乎我在这里丢失了日期列或东西。)
  • 非常感谢,我只是想知道这是否是dplyr 问题。 @Frank,是的,它们都有效。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-08-01
  • 1970-01-01
  • 2014-11-22
  • 1970-01-01
  • 2021-06-21
  • 2023-02-02
  • 1970-01-01
相关资源
最近更新 更多