group_by() 到 fill() 没有按预期工作
Posted
技术标签:
【中文标题】group_by() 到 fill() 没有按预期工作【英文标题】:group_by() into fill() not working as expected 【发布时间】:2016-04-03 17:03:15 【问题描述】:我正在尝试使用dplyr
和tidyr
对一些格式不正确的数据执行最后一次观察结转操作。它没有像我预期的那样工作。
library(dplyr)
library(tidyr)
df <- data.frame(id=c(1,1,2,2,3,3),
email=c('bob@email.com', NA, 'joe@email.com', NA, NA, NA))
df2 <- df %>% group_by(id) %>% fill(email)
这会导致:
Source: local data frame [6 x 2]
Groups: id [3]
id email
(dbl) (fctr)
1 1 bob@email.com
2 1 bob@email.com
3 2 joe@email.com
4 2 joe@email.com
5 3 joe@email.com
6 3 joe@email.com
我希望它是:
Source: local data frame [6 x 2]
Groups: id [3]
id email
(dbl) (fctr)
1 1 bob@email.com
2 1 bob@email.com
3 2 joe@email.com
4 2 joe@email.com
5 3 NA
6 3 NA
我希望它是后者的原因是因为group_by
的文档说:“group_by
函数采用现有的 tbl 并将其转换为分组 tbl,其中“按组”执行操作。”本例中的组由id
变量确定,下面的操作为fill(email)
。但是,很明显它没有这样做。
在任何人问之前,如果字段都是character
而不是numeric
或factor
,这没有区别。
更新 @aosmith 在 Github 上指出了 this open issue。我要说的是,在这个问题得到解决之前,不会有适当的解决方案。其他一切都只是一种解决方法。因此,如果有人成功地 PR 解决了该问题并将其发布在此处,我很乐意将其标记为解决方案。
【问题讨论】:
在 github 仓库中好像有一个open issue 关于这个 如果您的问题是如何在没有fill
(目前似乎不尊重分组)的情况下在 dplyr 中执行此操作,则有重复的 here 和 here
感谢 Github 问题链接!我最终确实使用ddply()
和fill()
解决了问题,但我想问题存在的事实意味着正确的解决方案只能作为解决该问题的方法。
作为不需要zoo
的解决方法,请参阅Wojciech's answer over here。
【参考方案1】:
这个问题我遇到过好几次了,我确实担心用这个..
df2 <- df %>% group_by(id) %>% fill(email)
在大型数据集上,因为我的结果好坏参半,并找到了以下解决方法。与 map_df 一起使用的 split 函数可确保您将所做的任何事情应用于每个 id 和 map_df 的特定 df,然后像魔术一样重新绑定所有单独的 df。在许多其他情况下,它也被证明很方便。现在这个问题已经过时了,但仍然是一个有用的替代方案,可以避免 group_by()。
df %>% split(.$id) %>% map_df(function(x) x %>% fill(email))
【讨论】:
【参考方案2】:看起来这已在 tidyr 的开发版本中得到修复。您现在使用来自 tidyr_0.3.1.9000 的 fill
获得每个 id 的预期结果。
df %>% group_by(id) %>% fill(email)
Source: local data frame [6 x 2]
Groups: id [3]
id email
(dbl) (fctr)
1 1 bob@email.com
2 1 bob@email.com
3 2 joe@email.com
4 2 joe@email.com
5 3 NA
6 3 NA
【讨论】:
确实,这在 CRAN 中可用的新 0.4.0 版本中已修复。【参考方案3】:另一种选择是使用来自dplyr
的do
:
df3 <- df %>% group_by(id) %>% do(fill(.,email))
【讨论】:
这可能是列出的最佳解决方法。但是,我仍然会坚持我上面的说明,在对包进行修复之前,它没有得到正确的回答。谢谢!【参考方案4】:这有点难看,但它是另一种使用 dplyr
并适用于您的示例数据的选项
df %>%
group_by(id) %>%
mutate(email = email[ !is.na(email) ][1])
【讨论】:
【参考方案5】:幸运的是,您仍然可以为此使用 zoo::na.locf
:
df %>%
group_by(id) %>%
mutate(email = zoo::na.locf(email, na.rm = FALSE))
# Source: local data frame [6 x 2]
# Groups: id [3]
#
# id email
# (dbl) (fctr)
# 1 1 bob@email.com
# 2 1 bob@email.com
# 3 2 joe@email.com
# 4 2 joe@email.com
# 5 3 NA
# 6 3 NA
【讨论】:
好主意,但我和我的同事认为使用主要目的是数据标准化的时间序列分析的包是不好的做法。如果这是一个时间序列问题,那将是公平的游戏,但不是在这里。【参考方案6】:两个问题,是不是重复了,一定要用dplyr
和tidyr
吗?
也许这可能是一个解决方案?
(
bar <- data.frame(id=c(1,1,2,2,3,3),
email=c('bob@email.com', NA, 'joe@email.com', NA, NA, NA))
)
#> id email
#> 1 bob@email.com
#> 1 <NA>
#> 2 joe@email.com
#> 2 <NA>
#> 3 <NA>
#> 3 <NA>
(
foo <- bar[!duplicated(bar$id),]
)
#> id email
#> 1 bob@email.com
#> 2 joe@email.com
#> 3 <NA>
【讨论】:
在我正在处理的实际数据中右侧还有更多数据,我只是想以最简洁的方式说明问题。以上是关于group_by() 到 fill() 没有按预期工作的主要内容,如果未能解决你的问题,请参考以下文章