使用 separate 拆分列中不均匀数量的变量
Using separate to split uneven number of variables in a column
我有这样的数据:
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
在预期输出中创建列名向量,然后在 [=] 中使用 'nm1' 指定 into
列19=].
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
使用 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
不要将整个向量重复多次,而是将向量的每个元素重复多次。
我有这样的数据:
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
在预期输出中创建列名向量,然后在 [=] 中使用 'nm1' 指定 into
列19=].
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
使用 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
不要将整个向量重复多次,而是将向量的每个元素重复多次。