我有一个像这样的数据框:
df <- structure(list(A = c("3 of 5", "1 of 2", "1 of 3", "1 of 3",
"3 of 4", "2 of 7"), B = c("2 of 2", "2 of 4", "0 of 1", "0 of 0",
"0 of 0", "0 of 0"), C = c("10 of 21", "3 of 14", "11 of 34",
"10 of 35", "16 of 53", "17 of 62"), D = c("0 of 0", "0 of 0",
"0 of 0", "0 of 0", "0 of 0", "0 of 0"), E = c("8 of 16", "3 of 15",
"10 of 32", "6 of 28", "13 of 49", "9 of 48")), class = c("tbl_df",
"tbl", "data.frame"), row.names = c(NA, -6L))
df
|A |B |C |D |E |
|:------|:------|:--------|:------|:--------|
|3 of 5 |2 of 2 |10 of 21 |0 of 0 |8 of 16 |
|1 of 2 |2 of 4 |3 of 14 |0 of 0 |3 of 15 |
|1 of 3 |0 of 1 |11 of 34 |0 of 0 |10 of 32 |
|1 of 3 |0 of 0 |10 of 35 |0 of 0 |6 of 28 |
|3 of 4 |0 of 0 |16 of 53 |0 of 0 |13 of 49 |
|2 of 7 |0 of 0 |17 of 62 |0 of 0 |9 of 48 |
我想将每一列都分成2列,给我留下这样的东西:
|A_attempted |A_landed |B_attempted |B_landed |C_attempted |C_landed |D_attempted |D_landed |E_attempted |E_landed |
|:-----------|:--------|:-----------|:--------|:-----------|:--------|:-----------|:--------|:-----------|:--------|
|3 |5 |2 |2 |10 |21 |0 |0 |8 |16 |
|1 |2 |2 |4 |3 |14 |0 |0 |3 |15 |
|1 |3 |0 |1 |11 |34 |0 |0 |10 |32 |
|1 |3 |0 |0 |10 |35 |0 |0 |6 |28 |
|3 |4 |0 |0 |16 |53 |0 |0 |13 |49 |
|2 |7 |0 |0 |17 |62 |0 |0 |9 |48 |
到目前为止,我使用的方法是:
df %>%
separate(A, sep = " of ", remove = T, into = c("A_attempted", "A_landed")) %>%
separate(B, sep = " of ", remove = T, into = c("B_attempted", "B_landed")) %>%
separate(C, sep = " of ", remove = T, into = c("C_attempted", "C_landed")) %>%
separate(D, sep = " of ", remove = T, into = c("D_attempted", "D_landed")) %>%
separate(E, sep = " of ", remove = T, into = c("E_attempted", "E_landed"))
考虑到我有15个变量,这不是很好。我希望使用map
这里有一个答案:Apply tidyr::separate over multiple columns,但使用了不赞成使用的功能
答案 0 :(得分:3)
可以尝试:
library(tidyverse)
names(df) %>%
map(
function(x)
df %>%
select(x) %>%
separate(x,
into = paste0(x, c("_attempted", "_landed")),
sep = " of ")
) %>%
bind_cols()
输出:
# A tibble: 6 x 10
A_attempted A_landed B_attempted B_landed C_attempted C_landed D_attempted D_landed E_attempted E_landed
<chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr>
1 3 5 2 2 10 21 0 0 8 16
2 1 2 2 4 3 14 0 0 3 15
3 1 3 0 1 11 34 0 0 10 32
4 1 3 0 0 10 35 0 0 6 28
5 3 4 0 0 16 53 0 0 13 49
6 2 7 0 0 17 62 0 0 9 48
正如OP所建议的,我们确实可以避免使用map_dfc
的最后一步:
names(df) %>%
map_dfc(~ df %>%
select(.x) %>%
separate(.x,
into = paste0(.x, c("_attempted", "_landed")),
sep = " of ")
)
答案 1 :(得分:2)
一种方法:
library(tidyverse)
df %>%
rownames_to_column("id") %>%
gather(group, value, -id) %>%
separate(value, into = c("attempted", "landed"), sep = " of ") %>%
gather(key, value, -id, -group) %>%
unite(new, group, key, sep = "_" ) %>%
spread(new, value)
# A tibble: 6 x 11
id A_attempted A_landed B_attempted B_landed C_attempted C_landed D_attempted D_landed E_attempted E_landed
<chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr>
1 1 3 5 2 2 10 21 0 0 8 16
2 2 1 2 2 4 3 14 0 0 3 15
3 3 1 3 0 1 11 34 0 0 10 32
4 4 1 3 0 0 10 35 0 0 6 28
5 5 3 4 0 0 16 53 0 0 13 49
6 6 2 7 0 0 17 62 0 0 9 48
答案 2 :(得分:2)
还有另一种tidyverse
可能性
imap_dfc(df, ~ separate(tibble(.x), col = 1,
paste0(.y, c("_attempted", "_landed")),
sep = " of ", convert = TRUE))
# # A tibble: 6 x 10
# A_attempted A_landed B_attempted B_landed C_attempted C_landed D_attempted D_landed E_attempted E_landed
# <int> <int> <int> <int> <int> <int> <int> <int> <int> <int>
# 1 3 5 2 2 10 21 0 0 8 16
# 2 1 2 2 4 3 14 0 0 3 15
# 3 1 3 0 1 11 34 0 0 10 32
# 4 1 3 0 0 10 35 0 0 6 28
# 5 3 4 0 0 16 53 0 0 13 49
# 6 2 7 0 0 17 62 0 0 9 48
答案 3 :(得分:1)
我们可以使用cSplit
library(splitstackshape)
df1 <- cSplit(df, names(df), sep = "of", stripWhite = FALSE)
df1
# A_1 A_2 B_1 B_2 C_1 C_2 D_1 D_2 E_1 E_2
#1: 3 5 2 2 10 21 0 0 8 16
#2: 1 2 2 4 3 14 0 0 3 15
#3: 1 3 0 1 11 34 0 0 10 32
#4: 1 3 0 0 10 35 0 0 6 28
#5: 3 4 0 0 16 53 0 0 13 49
#6: 2 7 0 0 17 62 0 0 9 48
我们可以通过以下方式重命名
names(df1) <- c(outer(names(df), c("attempted", "landed"), paste, sep = "_"))
我们总是可以在基R中做事
do.call(cbind.data.frame,
lapply(df, function(x) do.call(rbind, strsplit(x, " of "))))
# A.1 A.2 B.1 B.2 C.1 C.2 D.1 D.2 E.1 E.2
#1 3 5 2 2 10 21 0 0 8 16
#2 1 2 2 4 3 14 0 0 3 15
#3 1 3 0 1 11 34 0 0 10 32
#4 1 3 0 0 10 35 0 0 6 28
#5 3 4 0 0 16 53 0 0 13 49
#6 2 7 0 0 17 62 0 0 9 48
我们可以使用类似于上图所示的方式来重命名列。
答案 4 :(得分:1)
另一种整理方法:
purrr::map_dfc(names(df), function(i) {
df %>% separate(i,
sep = "of",
remove = T,
into = c(paste0(i, "_attempted"), paste0(i, "_landed")))
}) %>% dplyr::select(., contains("_"))