如何解决如何使用purrr :: map遍历两个连续的索引对象?
我有100多个csv文件,所有文件都具有相同的结构。每个csv文件都是系统中所有文档的元数据的每日快照。文件名包含快照日期。元数据包含Document_ID,状态,作者和其他一些列。每行代表文档的元数据。
我想创建一个随时间变化的日志。因此,我首先使用:
df <- fs::dir_ls(path = "Files") %>%
purrr::map_dfr(read_csv,.id = "Filename")
包含快照日期的原始文件名现在位于第一列中。这是生成的df的简化表示:
library(tidyverse)
df <- tibble(Filename = c(rep("File_2020-09-27",2),rep("File_2020-09-28",3),rep("File_2020-09-29",4),rep("File_2020-09-30",5)),Doc_ID = c(seq(1,seq(1,Status = c("Finished","Started","Finished","Waiting","Started"),Author = c("John","John","Mike","Betty"),Other_column = rnorm(14))
df
#> # A tibble: 14 x 5
#> Filename Doc_ID Status Author Other_column
#> <chr> <int> <chr> <chr> <dbl>
#> 1 File_2020-09-27 1 Finished John 0.319
#> 2 File_2020-09-27 2 Started John 0.633
#> 3 File_2020-09-28 1 Finished John 2.27
#> 4 File_2020-09-28 2 Started Mike 0.302
#> 5 File_2020-09-28 3 Started John 0.905
#> 6 File_2020-09-29 1 Finished John 0.451
#> 7 File_2020-09-29 2 Started Mike 1.46
#> 8 File_2020-09-29 3 Finished John 0.306
#> 9 File_2020-09-29 4 Started Mike -0.850
#> 10 File_2020-09-30 1 Finished John -2.03
#> 11 File_2020-09-30 2 Waiting Mike 0.250
#> 12 File_2020-09-30 3 Finished John 0.637
#> 13 File_2020-09-30 4 Started Mike -0.207
#> 14 File_2020-09-30 5 Started Betty -2.13
由reprex package(v0.3.0)于2020-10-02创建
请注意,文档永远不会消失,它们只会更改其状态或作者。要手动创建所需的输出,我首先为每个每日快照创建单独的小标题:
Docs_1 <- df %>% filter(Filename == "File_2020-09-27")
Docs_2 <- df %>% filter(Filename == "File_2020-09-28")
Docs_3 <- df %>% filter(Filename == "File_2020-09-29")
Docs_4 <- df %>% filter(Filename == "File_2020-09-30")
然后,对于每对连续的每日快照,我确定第二天的行,这些行是新的或与前一天不同。我只对这些感兴趣。 “新”或“不同”与Doc_ID
,Status
和Author
的组合有关:
Changes_1_2 <- Docs_2 %>% dplyr::anti_join(Docs_1,by = c("Doc_ID","Status","Author"))
导致:
# A tibble: 2 x 5
Filename Doc_ID Status Author Other_column
<chr> <int> <chr> <chr> <dbl>
1 File_2020-09-28 2 Started Mike 0.807
2 File_2020-09-28 3 Started John 0.336
Changes_2_3 <- Docs_3 %>% dplyr::anti_join(Docs_2,"Author"))
导致:
# A tibble: 2 x 5
Filename Doc_ID Status Author Other_column
<chr> <int> <chr> <chr> <dbl>
1 File_2020-09-29 3 Finished John 1.48
2 File_2020-09-29 4 Started Mike -0.0407
Changes_3_4 <- Docs_4 %>% dplyr::anti_join(Docs_3,"Author"))
导致:
# A tibble: 2 x 5
Filename Doc_ID Status Author Other_column
<chr> <int> <chr> <chr> <dbl>
1 File_2020-09-30 2 Waiting Mike -0.267
2 File_2020-09-30 5 Started Betty -1.36
最后,我将所有更改绑定在一起,以便在一个小标题中记录所有更改:
Changelog <- dplyr::bind_rows(Changes_1_2,Changes_2_3,Changes_3_4)
导致:
# A tibble: 6 x 5
Filename Doc_ID Status Author Other_column
<chr> <int> <chr> <chr> <dbl>
1 File_2020-09-28 2 Started Mike 0.807
2 File_2020-09-28 3 Started John 0.336
3 File_2020-09-29 3 Finished John 1.48
4 File_2020-09-29 4 Started Mike -0.0407
5 File_2020-09-30 2 Waiting Mike -0.267
6 File_2020-09-30 5 Started Betty -1.36
然后,我可以针对每个Doc_ID
在变更日志中分析其元数据随时间的变化。
鉴于文件和条目的绝对数量,我需要一个更优雅的解决方案来创建Changelog。如何使用迭代来实现此过程,最好使用purrr::map()
的{{1}}函数?我的问题是每次迭代都以两个连续的索引对象为目标,而我在任何地方都找不到这样的示例。我在想这样的事情(显然,这段代码行不通,只是发明了自己的说明用插图):
tidyverse
有人知道如何解决这个问题吗?也许我还应该将csv文件的初始加载更改为列表,而不是将其加载为单个小标题。
解决方法
我认为我们可以分组/嵌套,滞后和比较:
library(dplyr)
library(tidyr) # unnest
set.seed(42) # and then your `df <- tibble(...)`
df %>%
nest_by(Filename) %>%
ungroup() %>%
mutate(lastdata = lag(data)) %>%
filter(lengths(lastdata) > 0) %>%
mutate(
diffs = purrr::map2(data,lastdata,~ anti_join(.x,.y,by = c("Doc_ID","Status","Author")))
) %>%
select(-data,-lastdata) %>%
tidyr::unnest(diffs)
# # A tibble: 6 x 5
# Filename Doc_ID Status Author Other_column
# <chr> <int> <chr> <chr> <dbl>
# 1 File_2020-09-28 2 Started Mike 0.633
# 2 File_2020-09-28 3 Started John 0.404
# 3 File_2020-09-29 3 Finished John -0.0947
# 4 File_2020-09-29 4 Started Mike 2.02
# 5 File_2020-09-30 2 Waiting Mike 1.30
# 6 File_2020-09-30 5 Started Betty -0.279
要查看的重要步骤是:
-
初始分组/嵌套设置:
df %>% nest_by(Filename) %>% ungroup() %>% mutate(lastdata = lag(data)) # # A tibble: 4 x 3 # Filename data lastdata # <chr> <list<tbl_df[,4]>> <list<tbl_df[,4]>> # 1 File_2020-09-27 [2 x 4] [0] # 2 File_2020-09-28 [3 x 4] [2 x 4] # 3 File_2020-09-29 [4 x 4] [3 x 4] # 4 File_2020-09-30 [5 x 4] [4 x 4]
其中
data
列实际上包含您的Docs_1
至Docs_2
,而lastdata
包含data
的上一个。这意味着对于第二行,data
包含来自09-28
的行,lastdata
包含来自09-27
的行。 -
由于我们无法将
09-27
与前一天进行比较(并且其lastdata
为空),因此我们将其过滤掉了:filter(lengths(lastdata) > 0)
-
最后,我们遍历各列,
anti_join
依次lastdata
和data
每对:mutate( diffs = purrr::map2(data,"Author"))) ) # # A tibble: 3 x 4 # Filename data lastdata diffs # <chr> <list<tbl_df[,4]>> <list> # 1 File_2020-09-28 [3 x 4] [2 x 4] <tibble [2 x 4]> # 2 File_2020-09-29 [4 x 4] [3 x 4] <tibble [2 x 4]> # 3 File_2020-09-30 [5 x 4] [4 x 4] <tibble [2 x 4]>
-
通过删除和取消嵌套进行清理。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。