拆分字符串而不丢失字符- R
Split String without losing character- R
我在一个更大的数据框中有两列,我很难拆分。过去,当我尝试使用 "space"、"," 或其他分隔符进行拆分时,我曾使用过 strsplit
。这里最困难的部分是我不想丢失任何信息,当我拆分某些部分时,我最终会丢失信息。我想最终得到四列。这是我现在拥有的几行示例。
age-gen surv-camp
45M 1LC
9F 0
12M 1AC
67M 1LC
这是我最终想要得到的。
age gen surv camp
45 M 1 LC
9 F 0
12 M 1 AC
67 M 1 LC
我在这里做了很多搜索,并在 Java、C++、html 等中找到了许多响应,但我没有找到任何可以解释的内容如何在 R 中执行此操作以及何时丢失数据。
我看到 this 关于在值之间添加 space 然后在 space 上拆分,但我不知道这将如何工作 1) 缺少数据, 2) 当我在每一行中没有一致的数字或字符值时。
我们遍历 'df1' (lapply(df1, ..
) 的列,使用 sub
在数字子字符串后创建一个分隔符,将 vector
读为 data.frame 与 read.table
、rbind
和 data.frames
的 list
并更改输出的列名称。
res <- do.call(cbind, lapply(df1, function(x)
read.table(text=sub("(\d+)", "\1,", x),
header=FALSE, sep=",", stringsAsFactors=FALSE)))
colnames(res) <- scan(text=names(df1), sep=".", what="", quiet = TRUE)
res
# age gen surv camp
#1 45 M 1 LC
#2 9 F 0
#3 12 M 1 AC
#4 67 M 1 LC
或使用 separate
来自 tidyr
library(tidyr)
library(dplyr)
separate(df1, age.gen, into = c("age", "gen"), "(?<=\d)(?=[A-Za-z])", convert= TRUE) %>%
separate(surv.camp, into = c("surv", "camp"), "(?<=\d)(?=[A-Za-z])", convert = TRUE)
# age gen surv camp
#1 45 M 1 LC
#2 9 F 0 <NA>
#3 12 M 1 AC
#4 67 M 1 LC
或者如@Frank 所述,我们可以使用 data.table
中的 tstrsplit
library(data.table)
setDT(df1)[, unlist(lapply(.SD, function(x)
tstrsplit(x, "(?<=[0-9])(?=[a-zA-Z])", perl=TRUE,
type.convert=TRUE)), recursive = FALSE)]
编辑:在 separate
中添加了 convert = TRUE
以更改拆分后的列的 type
。
数据
df1 <- structure(list(age.gen = c("45M", "9F", "12M", "67M"), surv.camp = c("1LC",
"0", "1AC", "1LC")), .Names = c("age.gen", "surv.camp"),
class = "data.frame", row.names = c(NA, -4L))
我在一个更大的数据框中有两列,我很难拆分。过去,当我尝试使用 "space"、"," 或其他分隔符进行拆分时,我曾使用过 strsplit
。这里最困难的部分是我不想丢失任何信息,当我拆分某些部分时,我最终会丢失信息。我想最终得到四列。这是我现在拥有的几行示例。
age-gen surv-camp
45M 1LC
9F 0
12M 1AC
67M 1LC
这是我最终想要得到的。
age gen surv camp
45 M 1 LC
9 F 0
12 M 1 AC
67 M 1 LC
我在这里做了很多搜索,并在 Java、C++、html 等中找到了许多响应,但我没有找到任何可以解释的内容如何在 R 中执行此操作以及何时丢失数据。
我看到 this 关于在值之间添加 space 然后在 space 上拆分,但我不知道这将如何工作 1) 缺少数据, 2) 当我在每一行中没有一致的数字或字符值时。
我们遍历 'df1' (lapply(df1, ..
) 的列,使用 sub
在数字子字符串后创建一个分隔符,将 vector
读为 data.frame 与 read.table
、rbind
和 data.frames
的 list
并更改输出的列名称。
res <- do.call(cbind, lapply(df1, function(x)
read.table(text=sub("(\d+)", "\1,", x),
header=FALSE, sep=",", stringsAsFactors=FALSE)))
colnames(res) <- scan(text=names(df1), sep=".", what="", quiet = TRUE)
res
# age gen surv camp
#1 45 M 1 LC
#2 9 F 0
#3 12 M 1 AC
#4 67 M 1 LC
或使用 separate
来自 tidyr
library(tidyr)
library(dplyr)
separate(df1, age.gen, into = c("age", "gen"), "(?<=\d)(?=[A-Za-z])", convert= TRUE) %>%
separate(surv.camp, into = c("surv", "camp"), "(?<=\d)(?=[A-Za-z])", convert = TRUE)
# age gen surv camp
#1 45 M 1 LC
#2 9 F 0 <NA>
#3 12 M 1 AC
#4 67 M 1 LC
或者如@Frank 所述,我们可以使用 data.table
tstrsplit
library(data.table)
setDT(df1)[, unlist(lapply(.SD, function(x)
tstrsplit(x, "(?<=[0-9])(?=[a-zA-Z])", perl=TRUE,
type.convert=TRUE)), recursive = FALSE)]
编辑:在 separate
中添加了 convert = TRUE
以更改拆分后的列的 type
。
数据
df1 <- structure(list(age.gen = c("45M", "9F", "12M", "67M"), surv.camp = c("1LC",
"0", "1AC", "1LC")), .Names = c("age.gen", "surv.camp"),
class = "data.frame", row.names = c(NA, -4L))