问题描述
我有一个数据(当前为csv),其中包含一个带事件的变量(可以为空或包含最多30个由空格分隔的事件代码),然后每个事件的事件日期分别在单独的变量ED1,ED2,ED3中...
要从这些数据中获取有用的信息,我需要能够找到每个事件的日期。我的方法是将事件变量拆分为新行,但我对如何正确设置日期感到困扰。 (我正在使用R,因为稍后将使用它来分析数据,但我正在考虑也许切换到sql来管理数据)。
为简单起见,最多只能采样5个事件的数据:
# Sample data
df <- data.frame(ID = 1:5,E = c("FTT JAD AHN TKZ","","JAD FTT","AJN","TKZ AHD"),ED1 = as.Date(c("2016-04-01","2014-12-31","2019-05-15","2005-05-04")),ED2 = as.Date(c("2009-06-18","2007-11-12","2004-04-09")),ED3 = as.Date(c("2004-09-19","")),ED4 = as.Date(c("2012-07-15",ED5 = as.Date(NA))
# New variable with all dates
df %>%
unite(ED,ED1:ED5,sep=" ",na.rm=T) -> df
# Separate rows
df %>%
separate_rows(E,ED,sep=" ") -> df
这适用于此示例数据集,但是当我尝试将其应用于我的数据时,出现错误:
Error: Incompatible lengths: 4,2.
如果我是正确的话,这意味着E
和ED
会分成不同的行数。所以我认为数据集缺少数据。我试图用以下方法验证这一点:
df %>%
unite(ED,na.rm=T) %>%
mutate(E = strsplit(E," "),ED = strsplit(ED," ")) %>%
filter(length(E) != length(ED))
[1] ID E ED
<0 rows>
但是,如果我尝试分别在separate_rows()
或E
上ED
,则会得到不同数量的行。这就是我被困住的地方。
其他问题:
在另一个数据帧中,我想为每个ID
添加一个布尔值,如果该ID
参加了两个日期之间的特定事件类型或是否不基于此数据帧。每个ID
可以在事件数据帧中多次出现,并且每个ID可以多次参加相同类型的事件。
解决方法
问题显然是由于分隔E
值的空格数比ED
中的空格差这一事实引起的。为了解决这个问题,您可以只拆分E
列,并用空字符串填充值。
library(tidyverse)
#> Warning: package 'tibble' was built under R version 3.6.2
#> Warning: package 'purrr' was built under R version 3.6.2
# Sample data
df <- data.frame(ID = 1:5,E = c("FTT JAD AHN TKZ","","JAD FTT","AJN","TKZ AHD"),ED1 = as.Date(c("2016-04-01","2014-12-31","2019-05-15","2005-05-04")),ED2 = as.Date(c("2009-06-18","2007-11-12","2004-04-09")),ED3 = as.Date(c("2004-09-19","")),ED4 = as.Date(c("2012-07-15",ED5 = as.Date(NA),stringsAsFactors=F)
# testing
df %>%
mutate(E = strsplit(E," ")) %>%
# change 5 to 30 if you want to use this code on your data
filter(lengths(E) != 5)
#> ID E ED1 ED2 ED3 ED4 ED5
#> 1 1 FTT,JAD,AHN,TKZ 2016-04-01 2009-06-18 2004-09-19 2012-07-15 <NA>
#> 2 2 <NA> <NA> <NA> <NA> <NA>
#> 3 3 JAD,FTT 2014-12-31 2007-11-12 <NA> <NA> <NA>
#> 4 4 AJN 2019-05-15 <NA> <NA> <NA> <NA>
#> 5 5 TKZ,AHD 2005-05-04 2004-04-09 <NA> <NA> <NA>
df %>%
mutate( E=lapply(strsplit(E," "),function(x) c(x,rep("",5-length(x))) )) -> df.split
### First method keeps numerical format for date and NAs
df.split %>%
nest(ED=starts_with("ED")) %>%
mutate(ED=lapply(ED,function(x) unlist(x[1,],use.names=FALSE))) %>%
unnest(c(E,ED))
#> # A tibble: 25 x 3
#> ID E ED
#> <int> <chr> <dbl>
#> 1 1 "FTT" 16892
#> 2 1 "JAD" 14413
#> 3 1 "AHN" 12680
#> 4 1 "TKZ" 15536
#> 5 1 "" NA
#> 6 2 "" NA
#> 7 2 "" NA
#> 8 2 "" NA
#> 9 2 "" NA
#> 10 2 "" NA
#> # … with 15 more rows
### Second method Everything is a string
df.split %>%
unite(ED,ED1:ED5,sep=" ",na.rm=T)%>%
mutate( ED = strsplit(ED," ")) %>%
unnest(c(E,ED))
#> # A tibble: 25 x 3
#> ID E ED
#> <int> <chr> <chr>
#> 1 1 "FTT" 16892
#> 2 1 "JAD" 14413
#> 3 1 "AHN" 12680
#> 4 1 "TKZ" 15536
#> 5 1 "" NA
#> 6 2 "" NA
#> 7 2 "" NA
#> 8 2 "" NA
#> 9 2 "" NA
#> 10 2 "" NA
#> # … with 15 more rows
整齐
df%>%
separate(E,into=paste0("E",1:5),fill="right",sep=" ") %>%
unite(E,E1:E5,sep=" ") %>%
unite(ED,sep=" ") %>%
mutate(E=strsplit(E,ED=strsplit(ED," ")) %>%
unnest(c(E,ED)) %>% mutate(ED=as.Date(ED)) %>% filter(!is.na(ED))
#> ID E ED
#> <int> <chr> <date>
#> 1 1 FTT 2016-04-01
#> 2 1 JAD 2009-06-18
#> 3 1 AHN 2004-09-19
#> 4 1 TKZ 2012-07-15
#> 5 3 JAD 2014-12-31
#> 6 3 FTT 2007-11-12
#> 7 4 AJN 2019-05-15
#> 8 5 TKZ 2005-05-04
#> 9 5 AHD 2004-04-09