我的数据框如下:
df = data.frame(a = 1:4, strings = c('ooss_bboo_foo','ee_bbbbee_fffee','aas_baa_ffaa_daa', 'iisss_bbbbii_ffffii_dii_mii'))
我希望拆分_
,生成新列(或新数据框,并不重要)。可以使用min(lengths(strsplit(df$strings, "_")))
和max(lengths(strsplit(df$strings, "_")))
期望的输出:
X1 X2 X3
1 ooss bboo foo
2 ee bbbbee fffee
3 aas_baa ffaa daa
4 iisss_bbbbii_ffffii dii mii
我已经尝试了很多正则表达式,我已经非常绝望......
答案 0 :(得分:5)
以下是一些可能的解决方案:
1)gsubfn包中的read.pattern read.pattern
可以直接生成数据帧结果。没有使用其他包。它使用了一个特别简单的正则表达式。
首先我们创建模式pat
。例如,如果k
为3
,则pat
为"(.*)_(.*)_(.*)"
。然后,只需运行read.pattern
即可生成结果data.frame:
library(gsubfn)
strings <- as.character(df$strings) # ensure it's character, not factor
k <- min(lengths(strsplit(strings, "_"))) # from question
pat <- paste(rep("(.*)", k), collapse = "_")
read.pattern(text = strings, pattern = pat, as.is = TRUE)
,并提供:
V1 V2 V3
1 ooss bboo foo
2 ee bbbbee fffee
3 aas_baa ffaa daa
4 iisss_bbbbii_ffffii dii mii
2)sub / read.table 。相对于先前的解决方案,该解决方案涉及额外的步骤(sub
/ repl
部分);但是,它根本不使用任何包。它使用了上面的strings
,k
和pat
。如果k
等于3,则repl
的值为"\\1,\\2,\\3"
。
repl <- paste(paste0("\\", 1:k), collapse = ",")
read.table(text = sub(pat, repl, strings), sep = ",", as.is = TRUE)
给出相同的结果。 ","
的两个实例可以替换为数据中未找到的任何字符。
注意:在上面的解决方案中,我们使用as.is = TRUE
来使输出列成为字符,但如果因子是正确的则可以省略此参数。
答案 1 :(得分:3)
我已经假装了一支蛮力的&#34; stringi
版本。由于OP决定添加颜色评论,所以在接受的答案和这个答案之间进行比较(我在删除的评论中错了,我的速度比#34更少;但是更少但仍然是额外的包&#34 ;回答,如果那种事情对人们很重要):
library(stringi)
library(magrittr)
library(purrr)
library(gsubfn)
library(ggplot2)
library(microbenchmark)
df <- data.frame(a=1:4,
strings=c('ooss_bboo_foo',
'ee_bbbbee_fffee',
'aas_baa_ffaa_daa',
'iisss_bbbbii_ffffii_dii_mii'))
str_split_right_fixed <- function(str, pat, n) {
stri_reverse(df$strings) %>%
stri_split_fixed(pat, n) %>%
map_df(function(x) {
data.frame(rbind(rev(stri_reverse(x))), stringsAsFactors=FALSE)
})
}
gsubfn_split_fixed_right <- function(str, pat, n) {
pat <- paste(rep("(.*)", n), collapse = pat)
read.pattern(text = as.character(str), pattern = pat)
}
tab_split_fixed_right <- function(str, pat, n) {
repl <- paste(paste0("\\", 1:n), collapse = ",")
read.table(text = sub(pat, repl, str), sep = ",")
}
microbenchmark(str=str_split_right_fixed(df$strings, "_", 3),
gsb=gsubfn_split_fixed_right(df$strings, "_", 3),
tab=tab_split_fixed_right(df$strings, "_", 3),
times=1000) -> mb
autoplot(mb)