我有源数据,如下所示
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
答案 0 :(得分:1)
可能有更好的方法来做到这一点,不太确定,但这是一个tidyverse
的解决方案。该方法是为name
和phone
创建网站索引列,这些列使用spread
成为新的编号列名称。最后,我们可以使用summarise_at
为每个网站的每列选择第一个非缺失值。应该只有一个基于我们如何设置它,产生所需的格式。您可以使用select
和arrange
重新排序列和行。
编辑:更改为处理许多列。这个基本上将一些功能包装到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))