r语言 - 使用separate拆分列中不均匀数量的变量



我有这样的数据:

x <- c("France:4|Morroco:8|Italy:2", "Scotland:6|Mexico:2", "Scotland:2")
> player_country_info <- data.frame(x)
> setnames(player_country_info, "player_country_data")
> names(player_country_info)
[1] "player_country_data"
> is.data.frame(player_country_info)
[1] TRUE
> head(player_country_info)
                country_data
1 France:4|Morocco:8|Italy:2
2        Scotland:6|Mexico:2
3                 Scotland:2

我想要一个像这样的中间数据帧:

player_country_data.1   player_country_data.2   player_country_data.3
France:4                Morocco:8               Italy:2
Scotland:6              Mexico:2                NA
Scotland:2              NA                      NA

我计划然后使用dplyr::separate函数将上面的内容分开,使其看起来像这样,对每个列使用这个命令。

player_country_info %>% separate( col=player_country_data.1, into=c("country_name.1","player_count.1), sep=":")
country_name.1  player_count.1  country_name.2  player.2    country_name.3 player.3
France          4               Morocco         8           Italy           2
Scotland        6               Mexico          2
Scotland        2           

是否有更有效的方法来做到以上几点?也许是一个一步就能完成的命令?或者我应该在while循环之外用for循环来处理它?

谢谢

我们可以使用cSplit

一步完成此操作
library(splitstackshape)
cSplit(country_info, 'country_data', ':|\|', fixed = FALSE)

如果只需要中间步骤

cSplit(country_info, 'country_data', '|')

或者使用tidyr,我们使用outer在预期输出中创建列名向量,然后在separate中使用'nm1'指定into列。

library(tidyr)
nm1 <- c(outer(c('country_name.', 'player_count.'), 1:3, FUN = paste0))
separate(country_info, country_data, into = nm1, sep="[:|]")
#  country_name.1 player_count.1 country_name.2 player_count.2 country_name.3 player_count.3
#1         France              4        Morroco              8          Italy              2
#2       Scotland              6         Mexico              2           <NA>           <NA>
#3       Scotland              2           <NA>           <NA>           <NA>           <NA>

更新

使用注释中OP显示的新数据

separate(player_country_info2, player_country_data, into = nm1, sep="[:|]", convert= TRUE)
#  country_name.1 player_count.1 country_name.2 player_count.2 country_name.3 player_count.3
#1         France              4        Morocco             NA          Italy              2
#2       Scotland              6         Mexico              2           <NA>             NA
#3       Scotland              2           <NA>             NA           <NA>             NA

如果这是关于效率的,另一个选项是data.table中的tstrsplit

library(data.table)
setnames(setDT(country_info)[, tstrsplit(country_data, '[:|]', type.convert = TRUE)], nm1)[]
#  country_name.1 player_count.1 country_name.2 player_count.2 country_name.3 player_count.3
#1:         France              4        Morroco              8          Italy              2
#2:       Scotland              6         Mexico              2             NA             NA
#3:       Scotland              2             NA             NA             NA             NA

使用tidyr包中的separate:

library(tidyr)
country_info %>% 
  separate(country_data, 
           into = sprintf('%s.%s', rep(c('country','player.count'),3), rep(1:3, each=2)))
结果:

  country.1 player.count.1 country.2 player.count.2 country.3 player.count.3
1    France              4   Morroco              8     Italy              2
2  Scotland              6    Mexico              2      <NA>           <NA>
3  Scotland              2      <NA>           <NA>      <NA>           <NA>

Separate自动将:|识别为必须分隔的字符。如果希望在特定字符上进行分隔,则需要使用sep参数指定。在这种情况下,您可以使用sep = '[:|]'。这也可以防止在存在缺失值时自动检测的错误行为(参见注释中的讨论)。

使用sprintf,您将两个向量rep(c('country','player.count'),3)rep(1:3, each=2)粘贴到一个列名向量中,其中%s.%s告诉sprintf将这两个向量视为字符串向量并将它们粘贴在一起,并用点作为分隔符。参见?sprintf了解更多信息。参数each告诉rep不要重复整个向量多次,而是重复向量的每个元素多次。