R中的数据合并和清理

时间:2018-03-07 17:38:12

标签: r

我有源数据,如下所示

Site_Id    name    Phone
150        dan     916-654-8585
150        sasha   916-654-8794
150        Sam     916-654-8589
161        Jeff    916-654-8255
161        Danny   916-654-8535
120        Ali     916-654-8575

我编写了我的R代码,根据Site_ID的频率创建模板,因为最高频率为3,我的模板如下所示

Site_ID  name_1  Phone_1  name_2  Phone_2  name_3  Phone_3

我正在寻找一种方法将我的所有数据导入到模板中

结果我正在寻找:

Site_ID  name_1  Phone_1       name_2  Phone_2        name_3  Phone_3
150     dan     916-654-8585   sasha  916-654-8794    Sam     916-654-8589
161     Jeff    916-654-8255   Danny  916-654-8535    NA      NA
120     Ali     916-654-8575   NA     NA              NA      NA

2 个答案:

答案 0 :(得分:1)

可能有更好的方法来做到这一点,不太确定,但这是一个tidyverse的解决方案。该方法是为namephone创建网站索引列,这些列使用spread成为新的编号列名称。最后,我们可以使用summarise_at为每个网站的每列选择第一个非缺失值。应该只有一个基于我们如何设置它,产生所需的格式。您可以使用selectarrange重新排序列和行。

编辑:更改为处理许多列。这个基本上将一些功能包装到spread_var中,它有一个表和一个变量作为输入,并在标题情况下首先创建一个带有该变量的索引列,然后在索引列中传播该变量的值。我们确保在具有小写列名称的表上使用此函数,并按站点ID进行分组。处理sym()复杂的评估需要enquo!!:=dplyr,但至少它是按照书面形式运作的。可能会使它变得更简单,我不是超级练习。

调用函数非常简单,我们从colnames获取变量循环,每个循环展开另一个变量。最后一行与之前相同,折叠为第一个非缺失值。这样做的好处是,它可以处理site_id 任意数量的变量列的任意数量的变量。

EDIT2:使用受Prem启发的替代tidyverse方法进行了更新,但每个site_id的值超过3个值并不合适。但是,它确实适合一个管道,这很好。

library(tidyverse)
tbl <- read_table2(
  "Site_Id    name    Phone
150        dan     916-654-8585
150        sasha     916-654-8794
150        Sam     916-654-8589
161        Jeff    916-654-8255
161        Danny    916-654-8535
120        Ali     916-654-8575"
)
#> Warning in rbind(names(probs), probs_f): number of columns of result is not
#> a multiple of vector length (arg 2)
#> Warning: 1 parsing failure.
#> row # A tibble: 1 x 5 col     row col   expected actual        file         expected   <int> <chr> <chr>    <chr>         <chr>        actual 1     6 Phone ""       embedded null literal data file # A tibble: 1 x 5

spread_var <- function(df, var){
  varname <- rlang::sym(str_to_title(var))
  expr <- enquo(var)
  df %>%
    mutate(!!varname := row_number()) %>%
    spread(!!varname, !!expr, sep = "_")
}

out <- tbl %>%
  magrittr::set_colnames(str_to_lower(colnames(.))) %>%
  group_by(site_id)
for (i in colnames(out)[2:ncol(tbl)]){
  out <- spread_var(out, i)
}
out %>%
  summarise_at(vars(matches("_\\d$")), function(x) x[which(!is.na(x))[1]])
#> # A tibble: 3 x 7
#>   site_id Name_1 Name_2 Name_3 Phone_1      Phone_2      Phone_3     
#>     <int> <chr>  <chr>  <chr>  <chr>        <chr>        <chr>       
#> 1     120 Ali    <NA>   <NA>   916-654-8575 <NA>         <NA>        
#> 2     150 dan    sasha  Sam    916-654-8585 916-654-8589 916-654-8794
#> 3     161 Jeff   Danny  <NA>   916-654-8255 916-654-8535 <NA>

tbl %>%
  magrittr::set_colnames(str_to_lower(colnames(.))) %>%
  group_by(site_id) %>%
  summarise_all(~ str_c(., collapse = ",")) %>%
  imap_dfc(
    ~separate(
      data = tibble(.x),
      col = 1,
      into = c(str_c(.y, "_1"), str_c(.y, "_2"), str_c(.y, "_3")),
      sep = ",",
      fill = "right"
    )
  ) %>%
  select(-site_id_2, -site_id_3) %>%
  rename(site_id = site_id_1)
    #> # A tibble: 3 x 7
    #>   site_id Name_1 Name_2 Name_3 Phone_1      Phone_2      Phone_3     
    #>     <int> <chr>  <chr>  <chr>  <chr>        <chr>        <chr>       
    #> 1     120 Ali    <NA>   <NA>   916-654-8575 <NA>         <NA>        
    #> 2     150 dan    sasha  Sam    916-654-8585 916-654-8589 916-654-8794
    #> 3     161 Jeff   Danny  <NA>   916-654-8255 916-654-8535 <NA>

reprex package(v0.2.0)创建于2018-03-07。

答案 1 :(得分:1)

希望这有帮助!

library(dplyr)
library(splitstackshape)

df %>%
  group_by(Site_Id) %>%
  summarise_at(vars("name", "Phone"), funs(paste(., collapse=","))) %>%
  cSplit(c("name", "Phone"))

输出是:

   Site_Id name_1 name_2 name_3      Phone_1      Phone_2      Phone_3
1:     120    Ali     NA     NA 916-654-8575           NA           NA
2:     150    dan  sasha    Sam 916-654-8585 916-654-8794 916-654-8589
3:     161   Jeff  Danny     NA 916-654-8255 916-654-8535           NA

示例数据:

df <- structure(list(Site_Id = c(150L, 150L, 150L, 161L, 161L, 120L
), name = c("dan", "sasha", "Sam", "Jeff", "Danny", "Ali"), Phone = c("916-654-8585", 
"916-654-8794", "916-654-8589", "916-654-8255", "916-654-8535", 
"916-654-8575")), .Names = c("Site_Id", "name", "Phone"), class = "data.frame", row.names = c(NA, 
-6L))