对多列应用 tidyr::separate
Apply tidyr::separate over multiple columns
我想遍历数据框中的列,并根据分隔符将它们拆分为多个列。我正在使用 tidyr::separate
,当我一次只做一列时它会起作用。
例如:
df<- data.frame(a = c("5312,2020,1212"), b = c("345,982,284"))
df <- separate(data = df, col = "a",
into = paste("a", c("col1", "col2", "col3"),
sep = "_"), sep = ",")
Returns:
a_col1 a_col2 a_col3 b
1 5312 2020 1212 345,982,284
当我尝试对 df
R returns 的每一列执行相同的操作时出现错误
例如,我使用了这个 for 循环:
for(col in names(df)){
df <- separate(data = df, col = col,
into = paste(col, c("col1", "col2", "col3),
sep = "_"), sep = ",")
}
我期待得到以下输出:
a_col1 a_col2 a_col3 b_col1 b_col2 b_col3
1 5312 2020 1212 345 982 284
然而Rreturns这个错误:
Error in if (!after) c(values, x) else if (after >= lengx) c(x, values) else c(x[1L:after], :
argument is of length zero
是否有另一种方法可以将 tidyr::separate
应用于数据框中的多个列?
您可以将自定义 separate_()
调用输入 Reduce()
。
sep <- function(...) {
dots <- list(...)
n <- stringr::str_count(dots[[1]][[dots[[2]]]], "\d+")
separate_(..., into = sprintf("%s_col%d", dots[[2]], 1:n))
}
df %>% Reduce(f = sep, x = c("a", "b"))
# a_col_1 a_col_2 a_col_3 b_col_1 b_col_2 b_col_3
# 1 5312 2020 1212 345 982 284
否则cSplit
也会做
splitstackshape::cSplit(df, names(df))
# a_1 a_2 a_3 b_1 b_2 b_3
# 1: 5312 2020 1212 345 982 284
我也有同样的疑问(学习tidyverse
),就这样解决了。 N.B。我想要一个不会崩溃的解决方案,所以不依赖于知道 colnames。
library(tidyverse)
创建您的输入:
dft <- as_tibble(data.frame(a = c("5312,2020,1212"), b = c("345,982,284")))
df <- as.data.frame(dft)
创建一个空白小标题来收集输出:
dft0 <- read_csv("a\na")
dft0 <- dft0[,-1]
dft00 <- dft0
指定要分隔的元素的长度(可以做到in-loop,但我们通过查看dft
知道); N.B。如果您有更好的命名方式,请使用:
leng <- 3
For-loop版本:
for(x in 1:dim(df)[2]){
dataCol <- dft[,x]
newCols <- paste(colnames(dataCol)[1], paste("col", 1:leng, sep="") , sep="_")
dft0 <- cbind(dft0,
separate(data = dataCol,
col = colnames(dataCol)[1],
into = newCols,
sep = ","))}
乱七八糟的应用版本:
sapp <- sapply(colnames(df),function(ff){
separate(as_tibble(df[,ff]),
"value",
letters[1:leng],
sep=",")})
dft00 <- as_tibble(do.call(cbind, sapp))
colnames(dft00) <- as.vector(sapply(colnames(sapp),
function(sa){
paste(sa,
rownames(sapp),
sep="_")
}))
这适用于在单一语法中每列可变数量的分隔符。详细示例演示。
library(tidyverse)
df<- data.frame(a = c("5312,2020,1212", "21,4534"),
b = c("345,982,284", "324,234,3425,654"),
c = c('34,89,89', '87866675'))
df
#> a b c
#> 1 5312,2020,1212 345,982,284 34,89,89
#> 2 21,4534 324,234,3425,654 87866675
reduce(seq_along(df),
.init = df,
~ .x %>% separate(names(df)[.y],
sep = ',',
into = paste0(names(df)[.y], '_col_' , seq(1 + max(str_count(df[[.y]], ',')))),
fill = 'right'
)
)
#> a_col_1 a_col_2 a_col_3 b_col_1 b_col_2 b_col_3 b_col_4 c_col_1 c_col_2
#> 1 5312 2020 1212 345 982 284 <NA> 34 89
#> 2 21 4534 <NA> 324 234 3425 654 87866675 <NA>
#> c_col_3
#> 1 89
#> 2 <NA>
由 reprex package (v2.0.0)
于 2021-07-19 创建
我想遍历数据框中的列,并根据分隔符将它们拆分为多个列。我正在使用 tidyr::separate
,当我一次只做一列时它会起作用。
例如:
df<- data.frame(a = c("5312,2020,1212"), b = c("345,982,284"))
df <- separate(data = df, col = "a",
into = paste("a", c("col1", "col2", "col3"),
sep = "_"), sep = ",")
Returns:
a_col1 a_col2 a_col3 b
1 5312 2020 1212 345,982,284
当我尝试对 df
R returns 的每一列执行相同的操作时出现错误
例如,我使用了这个 for 循环:
for(col in names(df)){
df <- separate(data = df, col = col,
into = paste(col, c("col1", "col2", "col3),
sep = "_"), sep = ",")
}
我期待得到以下输出:
a_col1 a_col2 a_col3 b_col1 b_col2 b_col3
1 5312 2020 1212 345 982 284
然而Rreturns这个错误:
Error in if (!after) c(values, x) else if (after >= lengx) c(x, values) else c(x[1L:after], :
argument is of length zero
是否有另一种方法可以将 tidyr::separate
应用于数据框中的多个列?
您可以将自定义 separate_()
调用输入 Reduce()
。
sep <- function(...) {
dots <- list(...)
n <- stringr::str_count(dots[[1]][[dots[[2]]]], "\d+")
separate_(..., into = sprintf("%s_col%d", dots[[2]], 1:n))
}
df %>% Reduce(f = sep, x = c("a", "b"))
# a_col_1 a_col_2 a_col_3 b_col_1 b_col_2 b_col_3
# 1 5312 2020 1212 345 982 284
否则cSplit
也会做
splitstackshape::cSplit(df, names(df))
# a_1 a_2 a_3 b_1 b_2 b_3
# 1: 5312 2020 1212 345 982 284
我也有同样的疑问(学习tidyverse
),就这样解决了。 N.B。我想要一个不会崩溃的解决方案,所以不依赖于知道 colnames。
library(tidyverse)
创建您的输入:
dft <- as_tibble(data.frame(a = c("5312,2020,1212"), b = c("345,982,284")))
df <- as.data.frame(dft)
创建一个空白小标题来收集输出:
dft0 <- read_csv("a\na")
dft0 <- dft0[,-1]
dft00 <- dft0
指定要分隔的元素的长度(可以做到in-loop,但我们通过查看dft
知道); N.B。如果您有更好的命名方式,请使用:
leng <- 3
For-loop版本:
for(x in 1:dim(df)[2]){
dataCol <- dft[,x]
newCols <- paste(colnames(dataCol)[1], paste("col", 1:leng, sep="") , sep="_")
dft0 <- cbind(dft0,
separate(data = dataCol,
col = colnames(dataCol)[1],
into = newCols,
sep = ","))}
乱七八糟的应用版本:
sapp <- sapply(colnames(df),function(ff){
separate(as_tibble(df[,ff]),
"value",
letters[1:leng],
sep=",")})
dft00 <- as_tibble(do.call(cbind, sapp))
colnames(dft00) <- as.vector(sapply(colnames(sapp),
function(sa){
paste(sa,
rownames(sapp),
sep="_")
}))
这适用于在单一语法中每列可变数量的分隔符。详细示例演示。
library(tidyverse)
df<- data.frame(a = c("5312,2020,1212", "21,4534"),
b = c("345,982,284", "324,234,3425,654"),
c = c('34,89,89', '87866675'))
df
#> a b c
#> 1 5312,2020,1212 345,982,284 34,89,89
#> 2 21,4534 324,234,3425,654 87866675
reduce(seq_along(df),
.init = df,
~ .x %>% separate(names(df)[.y],
sep = ',',
into = paste0(names(df)[.y], '_col_' , seq(1 + max(str_count(df[[.y]], ',')))),
fill = 'right'
)
)
#> a_col_1 a_col_2 a_col_3 b_col_1 b_col_2 b_col_3 b_col_4 c_col_1 c_col_2
#> 1 5312 2020 1212 345 982 284 <NA> 34 89
#> 2 21 4534 <NA> 324 234 3425 654 87866675 <NA>
#> c_col_3
#> 1 89
#> 2 <NA>
由 reprex package (v2.0.0)
于 2021-07-19 创建