根据R中的分隔符将单列转换为多列
Convert a single column into multiple columns based on delimiter in R
我有以下数据框:
ID Parts
-- -----
1 A:B::
2 X2:::
3 ::J4:
4 A:C:D:G4:X6
我想通过 :
分隔符将 Parts 列转换为多个列。所以它应该看起来像:
ID A B X2 J4 C D G4 X6 ........
-- - - -- -- - - -- --
1 A B na na na na na na
2 na na X2 na na na na na
3 na na na J4 na na na na
4 A na na na C D G4 X6
在那里我不会提前知道潜在的列数。
我在这方面遇到了我的对手 - delim 的 strsplit() 我可以做到,但只能在 Parts
列
中使用固定数量的实体
tidyr
中的 seperate
函数是您要找的吗?
https://tidyr.tidyverse.org/reference/separate.html
它可能需要一些花哨的正则表达式实现,但可能会起作用。
您可以组合使用 tidyr::seperate
、tidyr::pivot_wider
和 tidyr::pivot_longer
。首先你仍然可以使用strsplit
来确定列的数量将Parts
拆分为而不是唯一值的数量(工作原理):
library(dplyr)
library(tidyr)
library(stringr)
n_col <- max(stringr::str_count(df$Parts, ":")) + 1
df %>%
tidyr::separate(Parts, into = paste0("col", 1:n_col), sep = ":") %>%
dplyr::mutate(across(everything(), ~dplyr::na_if(., ""))) %>%
tidyr::pivot_longer(-ID) %>%
dplyr::select(-name) %>%
tidyr::drop_na() %>%
tidyr::pivot_wider(id_cols = ID,
names_from = value)
ID A B X2 J4 C D G4 X6
<int> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr>
1 1 A B NA NA NA NA NA NA
2 2 NA NA X2 NA NA NA NA NA
3 3 NA NA NA J4 NA NA NA NA
4 4 A NA NA NA C D G4 X6
工作原理
使用此代码您不需要知道唯一值的数量——枢轴会处理这个问题。您需要知道的是 Parts
将被拆分成多少个新列 seperate
。这很容易做到,只需计算定界符的数量并用 str_count
添加一个即可。这样你就有了合适的列数来用你的分隔符将 Parts
分隔成。
这是因为 pivot_longer
将创建一个包含重复 ID
的两列数据框和一个包含分隔值 Parts
的列——一个 ID
、Parts
配对。然后,当您使用 pivot_wider
时,会为 Parts
的每个唯一值自动创建列,并且该值保留在列中。此函数会在未找到 ID
和 Parts
组合的情况下自动填充 NA
。
逐条尝试 运行 以便在需要时更好地理解。
数据
lines <- "
ID Parts
1 A:B::
2 X2:::
3 ::J4:
4 A:C:D:G4:X6
"
df <- read.table(text = lines, header = T)
我有以下数据框:
ID Parts
-- -----
1 A:B::
2 X2:::
3 ::J4:
4 A:C:D:G4:X6
我想通过 :
分隔符将 Parts 列转换为多个列。所以它应该看起来像:
ID A B X2 J4 C D G4 X6 ........
-- - - -- -- - - -- --
1 A B na na na na na na
2 na na X2 na na na na na
3 na na na J4 na na na na
4 A na na na C D G4 X6
在那里我不会提前知道潜在的列数。
我在这方面遇到了我的对手 - delim 的 strsplit() 我可以做到,但只能在 Parts
列
tidyr
中的 seperate
函数是您要找的吗?
https://tidyr.tidyverse.org/reference/separate.html
它可能需要一些花哨的正则表达式实现,但可能会起作用。
您可以组合使用 tidyr::seperate
、tidyr::pivot_wider
和 tidyr::pivot_longer
。首先你仍然可以使用strsplit
来确定列的数量将Parts
拆分为而不是唯一值的数量(工作原理):
library(dplyr)
library(tidyr)
library(stringr)
n_col <- max(stringr::str_count(df$Parts, ":")) + 1
df %>%
tidyr::separate(Parts, into = paste0("col", 1:n_col), sep = ":") %>%
dplyr::mutate(across(everything(), ~dplyr::na_if(., ""))) %>%
tidyr::pivot_longer(-ID) %>%
dplyr::select(-name) %>%
tidyr::drop_na() %>%
tidyr::pivot_wider(id_cols = ID,
names_from = value)
ID A B X2 J4 C D G4 X6
<int> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr>
1 1 A B NA NA NA NA NA NA
2 2 NA NA X2 NA NA NA NA NA
3 3 NA NA NA J4 NA NA NA NA
4 4 A NA NA NA C D G4 X6
工作原理
使用此代码您不需要知道唯一值的数量——枢轴会处理这个问题。您需要知道的是 Parts
将被拆分成多少个新列 seperate
。这很容易做到,只需计算定界符的数量并用 str_count
添加一个即可。这样你就有了合适的列数来用你的分隔符将 Parts
分隔成。
这是因为 pivot_longer
将创建一个包含重复 ID
的两列数据框和一个包含分隔值 Parts
的列——一个 ID
、Parts
配对。然后,当您使用 pivot_wider
时,会为 Parts
的每个唯一值自动创建列,并且该值保留在列中。此函数会在未找到 ID
和 Parts
组合的情况下自动填充 NA
。
逐条尝试 运行 以便在需要时更好地理解。
数据
lines <- "
ID Parts
1 A:B::
2 X2:::
3 ::J4:
4 A:C:D:G4:X6
"
df <- read.table(text = lines, header = T)