拆分或分隔 uneven/unequal 个字符串,不带分隔符
Split or separate uneven/unequal strings with no delimiter
给定数据帧 df
:
x <- c("X1", "X2", "X3", "X4", "X5")
y <- c("00L0", "0", "00012L", "0123L0", "0D0")
df <- data.frame(x, y)
如何利用 tidyr::separate
将 y
字符串的每个字符放入单独的列(每个字符串位置一列)?
期望的输出:
x <- c("X1", "X2", "X3", "X4", "X5")
m1 <- c(0, 0, 0, 0, 0)
m2 <- c(0, NA, 0, 1, "D")
m3 <- c("L", NA, 0, 2, 0)
mN <- c(NA, NA, NA, NA, NA)
df <- data.frame(x, m1, m2, m3, mN)
mN 理论上可以达到 m100(100 列)或更高。
这行得通。它用空白而不是 NA
填充,但如果您愿意,可以更改 post-hoc。 (fill = 'right'
仅在对字符向量进行拆分时有效,对显式位置无效。)
maxchar = max(nchar(as.character(df$y)))
tidyr::separate(df, y, into = paste0("y", 1:maxchar), sep = 1:(maxchar - 1))
# x y1 y2 y3 y4 y5 y6
# 1 X1 0 0 L 0
# 2 X2 0
# 3 X3 0 0 0 1 2 L
# 4 X4 0 1 2 3 L 0
# 5 X5 0 D 0
这是一个基本的 R 方法。
# split the strings
temp <- strsplit(df$y, split="")
# maximum length of the list items
maxL <- max(sapply(temp, length))
# contstruct data.frame with NAs as fills
temp <- data.frame(do.call(rbind, lapply(temp, function(i) c(i, rep(NA, maxL-length(i))))))
# add to df
df <- cbind(x=df[, -2], temp)
结果是
x X1 X2 X3 X4 X5 X6
1 X1 0 0 L 0 <NA> <NA>
2 X2 0 <NA> <NA> <NA> <NA> <NA>
3 X3 0 0 0 1 2 L
4 X4 0 1 2 3 L 0
5 X5 0 D 0 <NA> <NA> <NA>
我在创建 df 时使用了 stringsAFactors=FALSE:
df <- data.frame(x, y, stringsAsFactors = F)
但是,如果我不这样做,这段代码会导致错误,正如@m0h3n 指出的那样。如果没有这种替代 data.frame 构造,则有必要将 df$y 包装在 as.character
中以将变量从因子强制转换为字符:
# split the strings
temp <- strsplit(as.character(df$y), split="")
感谢@m0h3n 指出这一点。
您可以使用 strsplit 将 y 列中的字符串拆分为单个字符:
> strsplit("00L0",c())
[[1]]
[1] "0" "0" "L" "0"
从您的数据框开始:
> df
x y
1 X1 00L0
2 X2 0
3 X3 00012L
4 X4 0123L0
5 X5 0D0
我解决了将这些字符放入列中的问题:
首先:使用ddply将y列中的所有字符串拆分并放在不同的行中
> ddply(df, .(x), summarise, v = 1:nchar(as.character(y)),
y = unlist(strsplit(as.character(y),c())))
x v y
1 X1 1 0
2 X1 2 0
3 X1 3 L
4 X1 4 0
5 X2 1 0
6 X3 1 0
7 X3 2 0
8 X3 3 0
9 X3 4 1
10 X3 5 2
11 X3 6 L
12 X4 1 0
13 X4 2 1
14 X4 3 2
15 X4 4 3
16 X4 5 L
17 X4 6 0
18 X5 1 0
19 X5 2 D
20 X5 3 0
第二种:使用reshape将具有相同x值的行转换为列
> reshape(ans, idvar=c("x"), timevar="v", direction="wide")
x y.1 y.2 y.3 y.4 y.5 y.6
1 X1 0 0 L 0 <NA> <NA>
5 X2 0 <NA> <NA> <NA> <NA> <NA>
6 X3 0 0 0 1 2 L
12 X4 0 1 2 3 L 0
18 X5 0 D 0 <NA> <NA> <NA>
这可能会使问题过于复杂,但这是我让它工作的唯一方法!
这是另一个 base R
选项,我们使用 gsub
在 'y' 列的每个字符之间创建一个分隔符 ,
,然后使用 [=15= 读取它]
cbind(df[1],read.csv(text=gsub("(?<=.)(?=.)", ",", df$y, perl=TRUE),
header=FALSE,fill=TRUE, na.strings = ""))
# x V1 V2 V3 V4 V5 V6
#1 X1 0 0 L 0 <NA> <NA>
#2 X2 0 <NA> <NA> NA <NA> <NA>
#3 X3 0 0 0 1 2 L
#4 X4 0 1 2 3 L 0
#5 X5 0 D 0 NA <NA> <NA>
或使用 tstrsplit
来自 data.table
mxr = max(nchar(as.character(df$y)))
setDT(df)[, paste0("y", seq(mxr)) := tstrsplit(y, "")]
给定数据帧 df
:
x <- c("X1", "X2", "X3", "X4", "X5")
y <- c("00L0", "0", "00012L", "0123L0", "0D0")
df <- data.frame(x, y)
如何利用 tidyr::separate
将 y
字符串的每个字符放入单独的列(每个字符串位置一列)?
期望的输出:
x <- c("X1", "X2", "X3", "X4", "X5")
m1 <- c(0, 0, 0, 0, 0)
m2 <- c(0, NA, 0, 1, "D")
m3 <- c("L", NA, 0, 2, 0)
mN <- c(NA, NA, NA, NA, NA)
df <- data.frame(x, m1, m2, m3, mN)
mN 理论上可以达到 m100(100 列)或更高。
这行得通。它用空白而不是 NA
填充,但如果您愿意,可以更改 post-hoc。 (fill = 'right'
仅在对字符向量进行拆分时有效,对显式位置无效。)
maxchar = max(nchar(as.character(df$y)))
tidyr::separate(df, y, into = paste0("y", 1:maxchar), sep = 1:(maxchar - 1))
# x y1 y2 y3 y4 y5 y6
# 1 X1 0 0 L 0
# 2 X2 0
# 3 X3 0 0 0 1 2 L
# 4 X4 0 1 2 3 L 0
# 5 X5 0 D 0
这是一个基本的 R 方法。
# split the strings
temp <- strsplit(df$y, split="")
# maximum length of the list items
maxL <- max(sapply(temp, length))
# contstruct data.frame with NAs as fills
temp <- data.frame(do.call(rbind, lapply(temp, function(i) c(i, rep(NA, maxL-length(i))))))
# add to df
df <- cbind(x=df[, -2], temp)
结果是
x X1 X2 X3 X4 X5 X6
1 X1 0 0 L 0 <NA> <NA>
2 X2 0 <NA> <NA> <NA> <NA> <NA>
3 X3 0 0 0 1 2 L
4 X4 0 1 2 3 L 0
5 X5 0 D 0 <NA> <NA> <NA>
我在创建 df 时使用了 stringsAFactors=FALSE:
df <- data.frame(x, y, stringsAsFactors = F)
但是,如果我不这样做,这段代码会导致错误,正如@m0h3n 指出的那样。如果没有这种替代 data.frame 构造,则有必要将 df$y 包装在 as.character
中以将变量从因子强制转换为字符:
# split the strings
temp <- strsplit(as.character(df$y), split="")
感谢@m0h3n 指出这一点。
您可以使用 strsplit 将 y 列中的字符串拆分为单个字符:
> strsplit("00L0",c())
[[1]]
[1] "0" "0" "L" "0"
从您的数据框开始:
> df
x y
1 X1 00L0
2 X2 0
3 X3 00012L
4 X4 0123L0
5 X5 0D0
我解决了将这些字符放入列中的问题:
首先:使用ddply将y列中的所有字符串拆分并放在不同的行中
> ddply(df, .(x), summarise, v = 1:nchar(as.character(y)),
y = unlist(strsplit(as.character(y),c())))
x v y
1 X1 1 0
2 X1 2 0
3 X1 3 L
4 X1 4 0
5 X2 1 0
6 X3 1 0
7 X3 2 0
8 X3 3 0
9 X3 4 1
10 X3 5 2
11 X3 6 L
12 X4 1 0
13 X4 2 1
14 X4 3 2
15 X4 4 3
16 X4 5 L
17 X4 6 0
18 X5 1 0
19 X5 2 D
20 X5 3 0
第二种:使用reshape将具有相同x值的行转换为列
> reshape(ans, idvar=c("x"), timevar="v", direction="wide")
x y.1 y.2 y.3 y.4 y.5 y.6
1 X1 0 0 L 0 <NA> <NA>
5 X2 0 <NA> <NA> <NA> <NA> <NA>
6 X3 0 0 0 1 2 L
12 X4 0 1 2 3 L 0
18 X5 0 D 0 <NA> <NA> <NA>
这可能会使问题过于复杂,但这是我让它工作的唯一方法!
这是另一个 base R
选项,我们使用 gsub
在 'y' 列的每个字符之间创建一个分隔符 ,
,然后使用 [=15= 读取它]
cbind(df[1],read.csv(text=gsub("(?<=.)(?=.)", ",", df$y, perl=TRUE),
header=FALSE,fill=TRUE, na.strings = ""))
# x V1 V2 V3 V4 V5 V6
#1 X1 0 0 L 0 <NA> <NA>
#2 X2 0 <NA> <NA> NA <NA> <NA>
#3 X3 0 0 0 1 2 L
#4 X4 0 1 2 3 L 0
#5 X5 0 D 0 NA <NA> <NA>
或使用 tstrsplit
来自 data.table
mxr = max(nchar(as.character(df$y)))
setDT(df)[, paste0("y", seq(mxr)) := tstrsplit(y, "")]