2017-02-13 20 views
0

我有一些非常脏数据我真的很挣扎清洁。这个问题的一个例子是下面:tidyr/dplyr - 扩频多变量重复的ID

ID NAME ADDRESS    EMAIL  PHN 
1 Alice 123 Street  [email protected] 5555555 
1 Alice 123 Street    <NA> 4444444 
2  Bob 9 Circle  [email protected] 1111111 
3 Charlie  4 Ave [email protected] 3333333 
3 Charlie  4 Ave [email protected] 3333333 
3 Charlie  4 Ave    <NA>  NA 
4 Doug 1 Court    <NA> 6666666 

所需的输出是这样的:

ID NAME ADDRESS   EMAIL_1    EMAIL_2 PHN_1 PHN_2 
1 Alice 123 Street [email protected]    <NA> 5555555 4444444 
2  Bob 9 Circle  [email protected]    <NA> 1111111  NA 
3 Charlie  4 Ave [email protected] [email protected] 3333333  NA 
4 Doug 1 Court    <NA>    <NA> 6666666  NA 

以理解可以存在的EMAILPHN变量的任意膨胀(即,存在可能是ID的ñ重复,其具有不同的(或NA)值)

我的解决方案到目前为止:

df.test <- df %>% 
    group_by(ID) %>% 
    mutate(EMAILID = paste0("EMAIL_",row_number())) %>% 
    spread(EMAILID,EMAIL) %>% 
    mutate(PHONEID = paste0('PHN_',row_number())) %>% 
    spread(PHONEID,PHN) 

但是,这会产生一个更加畸形data.frame:

ID NAME ADDRESS   EMAIL_1    EMAIL_2 EMAIL_3 PHN_1 PHN_2 PHN_3 
1 Alice 123 Street [email protected]    <NA> <NA> 5555555  NA NA 
1 Alice 123 Street    <NA>    <NA> <NA>  NA 4444444 NA 
2  Bob 9 Circle  [email protected]    <NA> <NA> 1111111  NA NA 
3 Charlie  4 Ave [email protected]    <NA> <NA> 3333333  NA NA 
3 Charlie  4 Ave    <NA> [email protected] <NA>  NA 3333333 NA 
3 Charlie  4 Ave    <NA>    <NA> <NA>  NA  NA NA 
4 Doug 1 Court    <NA>    <NA> <NA> 6666666  NA NA 

任何帮助吗?我怀疑我的问题是什么做的spread()命令,但我尝试到目前为止已被证明相当无果而终。谢谢。

+0

,如果你花了变异,会发生什么? –

+0

@RyanMorton:如果我替换代码: '''df.test <- df %>% GROUP_BY(ID)%>% 传播(ID,电子邮件)%>% 传播(ID,PHN)''' 我得到错误:重复的标识符行(4,5) –

+0

嗯,你能添加名称到GROUP_BY? –

回答

2

您需要summarize而不是mutate,然后使用separate拆分结果。要做到这一点动态可以判断不同的电子邮件和电话团体使用的提前,使用separate_的数量,然后设置fill = right删除警告。最后两个mutate语句在那里收拾变成字符串NA值。

library(dplyr) 
library(tidyr) 

cols <- cols <- df %>% 
    group_by(ID) %>% 
    filter(!is.na(PHN), !is.na(EMAIL)) %>% 
    group_size() %>% 
    max() 

df %>% 
    group_by(ID, NAME, ADDRESS) %>% 
    summarize_each(funs(toString(unique(.[!is.na(.)]))), EMAIL, PHN) %>% 
    separate_("EMAIL", sprintf("EMAIL%s", 1:cols), sep = ",", fill = "right") %>% 
    separate_("PHN", sprintf("PHN%s", 1:cols), sep = ",", fill = "right") %>% 
    mutate_if(is.character, trimws) %>% 
    mutate_each(funs(replace(., grep("NA", .), NA))) 

    Source: local data frame [4 x 7] 
Groups: ID, NAME [4] 

    ID NAME ADDRESS   EMAIL1    EMAIL2 PHN1 PHN2 
    <int> <fctr>  <fctr>    <chr>    <chr> <chr> <chr> 
1  1 Alice 123 Street [email protected]    <NA> 5555555 4444444 
2  2  Bob 9 Circle  [email protected]    <NA> 1111111 <NA> 
3  3 Charlie  4 Ave [email protected] [email protected] 3333333 <NA> 
4  4 Doug 1 Court    <NA>    <NA> 6666666 <NA> 

的警告将被抛出

+0

)这是否会给您带来很多错误?输出是正确的,但我收到了运行时发生此错误列表: '''警告消息: 1:1个位置的值太多:3 2:2个位置的值太小:2,3:1个位置的值过多:3 4:在2个位置的值太少:2,4''' –

+0

你会得到警告,而不是错误,警告是引用由某些组合产生的额外项目大于分割列的数目。 '看看我的笔记'separate_' –

+0

啊哈!它适用于我的非示例数据。谢谢! –

0

1)重塑使用基础R这可以在3行来完成。代码的第一行添加的序列号对于每个ID和最后执行转换从长到宽。第二行代码将数据帧从长整型变为宽整型,最后一行代码将删除仅包含NAs的列。 (如果来港的列是不可能的,或者你不介意他们,那么代码的第三行可以省略。)

df2 <- transform(df.test, seq = ave(ID, ID, FUN = seq_along)) 
df2 <- reshape(df2, dir = "wide", timevar = "seq", idvar = c("ID", "NAME", "ADDRESS")) 
subset(df2, select = !apply(is.na(df.test2), 2, all)) 

,并提供:

ID NAME ADDRESS   EMAIL.1 PHN.1    EMAIL.2 PHN.2 
1 1 Alice 123 Street [email protected] 5555555    <NA> 4444444 
3 2  Bob 9 Circle  [email protected] 1111111    <NA>  NA 
4 3 Charlie  4 Ave [email protected] 3333333 [email protected] 3333333 
7 4 Doug 1 Court    <NA> 6666666    <NA>  NA 

2)magrittr同样的代码,除了形成一个magrittr管道可以写为:

library(magrittr) 

df.test %>% 
    transform(seq = ave(ID, ID, FUN = seq_along)) %>% 
    reshape(dir = "wide", timevar = "seq", idvar = c("ID", "NAME", "ADDRESS")) %>% 
    subset(select = !apply(is.na(.), 2, all)) 

注:输入df.test可再现的形式是:

Lines <- " 
ID,NAME,ADDRESS,EMAIL,PHN 
1,Alice,123 Street,[email protected],5555555 
1,Alice,123 Street,NA,4444444 
2,Bob,9 Circle,[email protected],1111111 
3,Charlie,4 Ave,[email protected],3333333 
3,Charlie,4 Ave,[email protected],3333333 
3,Charlie,4 Ave,NA, 
4,Doug,1 Court,NA,6666666" 
df.test <- read.csv(text=Lines)