使用单独分割列中的不均匀数量的变量

时间:2016-11-06 14:57:10

标签: r split tidyr

我有这样的数据:

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循环处理它吗?

由于

2 个答案:

答案 0 :(得分:3)

我们可以使用cSplit

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

如果我们只需要中间步骤

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

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

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

如果这是关于效率的,另一个选项是来自tstrsplit

data.table
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

答案 1 :(得分:1)

separate包中的tidyr

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>

单独自动识别:|作为必须分开的字符。如果要分隔特定字符,则需要使用sep参数指定该字符。在这种情况下,您可以使用sep = '[:|]'。这也可以防止在缺少值时自动检测的不当行为(请参阅注释中的讨论)。

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