将全名向量拆分为 2 个独立向量的有效方法
Efficient way to split a vector of a full name in to 2 separate vectors
我有一个由全名组成的向量,名字和姓氏用逗号分隔这就是前几个元素的样子:
> head(val.vec)
[1] "Aabye,ֲ Edgar" "Aaltonen,ֲ Arvo" "Aaltonen,ֲ Paavo"
[4] "Aalvik Grimsb,ֲ Kari" "Aamodt,ֲ Kjetil Andr" "Aamodt,ֲ Ragnhild
我正在寻找一种方法将它们分成 2 个单独的名字和姓氏列。我的最终目的是将它们都作为更大数据框架的一部分。
我试过像这样使用 strsplit
函数
names<-unlist(strsplit(val.vec,','))
但它给了我一个长向量而不是 2 个单独的集合,我知道它是
可以使用循环并遍历所有元素并将名字和姓氏放在 2 个单独的向量中,但考虑到大约有 25000 条记录这一事实有点耗时。
我看到了一些类似的问题,但讨论的是如何在 C+ 上进行,Java
我们可以使用 read.csv
将 vector
转换为具有 2 列的 data.frame
read.csv(text=val.vec, header=FALSE, stringsAsFactors=FALSE)
或者如果我们使用 strsplit
,而不是 unlist
ing(这会将整个 list
转换为单个 vector
),我们可以提取第一个和 list
中的第二个元素分别创建两个 vector
('v1' 和 'v2')。
lst <- strsplit(val.vec,',')
v1 <- lapply(lst, `[`, 1)
v2 <- lapply(lst, `[`, 2)
另一个选择是 sub
v1 <- sub(",.*", "", val.vec)
v2 <- sub("[^,]+,", "", val.vec)
数据
val.vec <- c("Aabye,ֲ Edgar", "Aaltonen,ֲ Arvo", "Aaltonen,ֲ Paavo",
"Aalvik Grimsb,ֲ Kari", "Aamodt,ֲ Kjetil Andr", "Aamodt,ֲ Ragnhild")
只需将您的函数调用封装到 sapply
调用中即可:
val.vec = c("Aabye,ֲ Edgar", "Aaltonen,ֲ Arvo", "Aaltonen,ֲ Paavo", "Aalvik Grimsb,ֲ Kari", "Aamodt,ֲ Kjetil Andr", "Aamodt,ֲ Ragnhild")
names = t(sapply(val.vec, function(x) unlist(strsplit(x,','))))
names
#> names
# [,1] [,2]
#Aabye,? Edgar "Aabye" "? Edgar"
#Aaltonen,? Arvo "Aaltonen" "? Arvo"
#Aaltonen,? Paavo "Aaltonen" "? Paavo"
#Aalvik Grimsb,? Kari "Aalvik Grimsb" "? Kari"
#Aamodt,? Kjetil Andr "Aamodt" "? Kjetil Andr"
#Aamodt,? Ragnhild "Aamodt" "? Ragnhild"
使用您尝试过的解决方案,我们可以将其强制为两列。
val.vec = c("Aabye,ֲ Edgar", "Aaltonen,ֲ Arvo", "Aaltonen,ֲ Paavo", "Aalvik Grimsb,ֲ Kari", "Aamodt,ֲ Kjetil Andr", "Aamodt,ֲ Ragnhild")
names = matrix(unlist(strsplit(val.vec,',')), ncol = 2L, byrow = TRUE)
#> names
# [,1] [,2]
#[1,] "Aabye" "? Edgar"
#[2,] "Aaltonen" "? Arvo"
#[3,] "Aaltonen" "? Paavo"
#[4,] "Aalvik Grimsb" "? Kari"
#[5,] "Aamodt" "? Kjetil Andr"
#[6,] "Aamodt" "? Ragnhild"
根据 Richard Scriven 提出的(非常快的)解决方案对其进行测试,我们可以看到你的和他的是等价的:
#> library(microbenchmark)
#> microbenchmark(
#+ names_1 = do.call(rbind, strsplit(val.vec, ",")),
#+ names_2 = matrix(unlist(strsplit(val.vec,',')), ncol = 2L, byrow = TRUE),
#+ times = 10000L
#+ )
#Unit: microseconds
# expr min lq mean median uq max neval cld
# names_1 12.596 13.530 15.08867 13.996 14.463 513.185 10000 b
# names_2 11.663 12.131 14.03413 12.597 13.530 1436.917 10000 a
另一个选项:
library(stringi)
stri_split_fixed(val.vec, ",", simplify = TRUE)
给出:
# [,1] [,2]
#[1,] "Aabye" "ֲ Edgar"
#[2,] "Aaltonen" "ֲ Arvo"
#[3,] "Aaltonen" "ֲ Paavo"
#[4,] "Aalvik Grimsb" "ֲ Kari"
#[5,] "Aamodt" "ֲ Kjetil Andr"
#[6,] "Aamodt" "ֲ Ragnhild"
如果您想要 data.frame
中的结果,您可以将其包装在 as.data.frame()
中
如果您喜欢 dplyr
做事方式,请查看 tidyr
包中的 separate
:
library(dplyr)
library(tidyr)
dat = data.frame(val = c("Lee, John", "Lee, Spike", "Doe, John",
"Longstocking, Pippy", "Bond, James", "Jordan, Michael"))
# val
# 1 Lee, John
# 2 Lee, Spike
# 3 Doe, John
# 4 Longstocking, Pippy
# 5 Bond, James
# 6 Jordan, Michael
dat %>%
separate(val, c('last_name', 'first_name'), sep = ',') %>%
mutate(first_name = trimws(first_name))
# last_name first_name
# 1 Lee John
# 2 Lee Spike
# 3 Doe John
# 4 Longstocking Pippy
# 5 Bond James
# 6 Jordan Michael
在对 trimws
的调用中添加以去除前导空格。
我有一个由全名组成的向量,名字和姓氏用逗号分隔这就是前几个元素的样子:
> head(val.vec)
[1] "Aabye,ֲ Edgar" "Aaltonen,ֲ Arvo" "Aaltonen,ֲ Paavo"
[4] "Aalvik Grimsb,ֲ Kari" "Aamodt,ֲ Kjetil Andr" "Aamodt,ֲ Ragnhild
我正在寻找一种方法将它们分成 2 个单独的名字和姓氏列。我的最终目的是将它们都作为更大数据框架的一部分。
我试过像这样使用 strsplit
函数
names<-unlist(strsplit(val.vec,','))
但它给了我一个长向量而不是 2 个单独的集合,我知道它是 可以使用循环并遍历所有元素并将名字和姓氏放在 2 个单独的向量中,但考虑到大约有 25000 条记录这一事实有点耗时。
我看到了一些类似的问题,但讨论的是如何在 C+ 上进行,Java
我们可以使用 read.csv
将 vector
转换为具有 2 列的 data.frame
read.csv(text=val.vec, header=FALSE, stringsAsFactors=FALSE)
或者如果我们使用 strsplit
,而不是 unlist
ing(这会将整个 list
转换为单个 vector
),我们可以提取第一个和 list
中的第二个元素分别创建两个 vector
('v1' 和 'v2')。
lst <- strsplit(val.vec,',')
v1 <- lapply(lst, `[`, 1)
v2 <- lapply(lst, `[`, 2)
另一个选择是 sub
v1 <- sub(",.*", "", val.vec)
v2 <- sub("[^,]+,", "", val.vec)
数据
val.vec <- c("Aabye,ֲ Edgar", "Aaltonen,ֲ Arvo", "Aaltonen,ֲ Paavo",
"Aalvik Grimsb,ֲ Kari", "Aamodt,ֲ Kjetil Andr", "Aamodt,ֲ Ragnhild")
只需将您的函数调用封装到 sapply
调用中即可:
val.vec = c("Aabye,ֲ Edgar", "Aaltonen,ֲ Arvo", "Aaltonen,ֲ Paavo", "Aalvik Grimsb,ֲ Kari", "Aamodt,ֲ Kjetil Andr", "Aamodt,ֲ Ragnhild")
names = t(sapply(val.vec, function(x) unlist(strsplit(x,','))))
names
#> names
# [,1] [,2]
#Aabye,? Edgar "Aabye" "? Edgar"
#Aaltonen,? Arvo "Aaltonen" "? Arvo"
#Aaltonen,? Paavo "Aaltonen" "? Paavo"
#Aalvik Grimsb,? Kari "Aalvik Grimsb" "? Kari"
#Aamodt,? Kjetil Andr "Aamodt" "? Kjetil Andr"
#Aamodt,? Ragnhild "Aamodt" "? Ragnhild"
使用您尝试过的解决方案,我们可以将其强制为两列。
val.vec = c("Aabye,ֲ Edgar", "Aaltonen,ֲ Arvo", "Aaltonen,ֲ Paavo", "Aalvik Grimsb,ֲ Kari", "Aamodt,ֲ Kjetil Andr", "Aamodt,ֲ Ragnhild")
names = matrix(unlist(strsplit(val.vec,',')), ncol = 2L, byrow = TRUE)
#> names
# [,1] [,2]
#[1,] "Aabye" "? Edgar"
#[2,] "Aaltonen" "? Arvo"
#[3,] "Aaltonen" "? Paavo"
#[4,] "Aalvik Grimsb" "? Kari"
#[5,] "Aamodt" "? Kjetil Andr"
#[6,] "Aamodt" "? Ragnhild"
根据 Richard Scriven 提出的(非常快的)解决方案对其进行测试,我们可以看到你的和他的是等价的:
#> library(microbenchmark)
#> microbenchmark(
#+ names_1 = do.call(rbind, strsplit(val.vec, ",")),
#+ names_2 = matrix(unlist(strsplit(val.vec,',')), ncol = 2L, byrow = TRUE),
#+ times = 10000L
#+ )
#Unit: microseconds
# expr min lq mean median uq max neval cld
# names_1 12.596 13.530 15.08867 13.996 14.463 513.185 10000 b
# names_2 11.663 12.131 14.03413 12.597 13.530 1436.917 10000 a
另一个选项:
library(stringi)
stri_split_fixed(val.vec, ",", simplify = TRUE)
给出:
# [,1] [,2]
#[1,] "Aabye" "ֲ Edgar"
#[2,] "Aaltonen" "ֲ Arvo"
#[3,] "Aaltonen" "ֲ Paavo"
#[4,] "Aalvik Grimsb" "ֲ Kari"
#[5,] "Aamodt" "ֲ Kjetil Andr"
#[6,] "Aamodt" "ֲ Ragnhild"
如果您想要 data.frame
中的结果,您可以将其包装在 as.data.frame()
如果您喜欢 dplyr
做事方式,请查看 tidyr
包中的 separate
:
library(dplyr)
library(tidyr)
dat = data.frame(val = c("Lee, John", "Lee, Spike", "Doe, John",
"Longstocking, Pippy", "Bond, James", "Jordan, Michael"))
# val
# 1 Lee, John
# 2 Lee, Spike
# 3 Doe, John
# 4 Longstocking, Pippy
# 5 Bond, James
# 6 Jordan, Michael
dat %>%
separate(val, c('last_name', 'first_name'), sep = ',') %>%
mutate(first_name = trimws(first_name))
# last_name first_name
# 1 Lee John
# 2 Lee Spike
# 3 Doe John
# 4 Longstocking Pippy
# 5 Bond James
# 6 Jordan Michael
在对 trimws
的调用中添加以去除前导空格。