拆分列,将结果列转换为因子
Split Column, convert resulting columns to factors
我的目标是将一个由 1 和 0 组成的字符列拆分成它们自己的列。我希望新列的类型为“因素”。我找到了一种拆分列的好方法(使用 dplyr 的“mutate”和 reshape2 的“colsplit”),但未能找到一种有效的方法来使所有结果列的类型为“factor”。
这是我的问题的一个最小示例:
library(dplyr)
library(reshape2)
# Data frame to be processed
df = tribble(
~x, ~y, ~z,
"Alpha", "1111", "Alp",
"Beta", "1001", "Bet"
)
# Vector Containing Names for columns
names = c("A", "B", "C", "D")
df %>%
mutate_at("y", colsplit, names = names, pattern = "")
输出:
# A tibble: 2 x 3
x y$A $B $C $D z
<chr> <int> <int> <int> <int> <chr>
1 Alpha 1 1 1 1 Alp
2 Beta 1 0 0 1 Bet
此示例生成正确的 table,只是我希望新列成为因子(下游脚本需要)。我还希望新列不使用有关旧列的信息命名,我认为这是 colsplit
的一个特征——指的是 y$
和 $
部分。
目前,我唯一能使所有列成为因子的方法是手动编辑它们,这是相当低效的。
我试过的其他解决方案:
我也尝试使用 tidyverse 中的 separate
来解决这个问题,但无法正确划分。我不明白它使用的是什么正则表达式。例如,这段代码:
df %>%
separate("y", into = names, sep = "")
结果:
# A tibble: 2 x 6
x A B C D z
<chr> <chr> <chr> <chr> <chr> <chr>
1 Alpha "" 1 1 1 Alp
2 Beta "" 1 0 0 Bet
哪个似乎是在选择字符串之前的第一个空格?我不太清楚那是怎么回事。
此外,实际上,第 y
列中的字符串可以是不同的长度(但在正在处理的数据集中将保持一致的大小——例如,y 可以是 100 个字符长,并且它每行将有 100 长)。
这是使用 dplyr
& tidyr
的方法
library(dplyr)
library(tidyr)
# Create a names vector that dynamic base on length of y index from 1 to max length
# As "" feed to separate as separator so the first matched is an empty char
# for this case we add a column to be dropped later into the names list.
names <- c("drop", seq_len(max(sapply(df$y, nchar))))
df %>%
separate("y", into = names, sep = "", fill = "warn") %>%
mutate_if(.predicate = is.character, .funs = factor) %>%
select(-drop)
#> # A tibble: 2 x 6
#> x `1` `2` `3` `4` z
#> <fct> <fct> <fct> <fct> <fct> <fct>
#> 1 Alpha 1 1 1 1 Alp
#> 2 Beta 1 0 0 1 Bet
或另一种方法,仅将 names
中出现的列转换为因子
df %>%
separate("y", into = names, sep = "") %>%
mutate_at(vars(one_of(names)), .funs = factor) %>%
select(-drop)
#> # A tibble: 2 x 6
#> x `1` `2` `3` `4` z
#> <chr> <fct> <fct> <fct> <fct> <chr>
#> 1 Alpha 1 1 1 1 Alp
#> 2 Beta 1 0 0 1 Bet
由 reprex package (v2.0.0)
于 2021-05-15 创建
我不太确定你的要求,但你可以做这样的事情(稍微改变你的 df,以表明不需要对 colnames 进行硬编码)
df = tribble(
~x, ~y, ~z,
"Alpha", "1111346767909", "Alp",
"Beta", "1001", "Bet"
)
# A tibble: 2 x 3
x y z
<chr> <chr> <chr>
1 Alpha 1111346767909 Alp
2 Beta 1001 Bet
df %>%
separate(y, into = paste0('y_', seq_len(1 + max(nchar(.$y)))-1), sep = '', fill = 'right' ) %>%
select(!ends_with('_0')) %>%
mutate(across(starts_with('y_'), factor))
# A tibble: 2 x 15
x y_1 y_2 y_3 y_4 y_5 y_6 y_7 y_8 y_9 y_10 y_11 y_12 y_13 z
<chr> <fct> <fct> <fct> <fct> <fct> <fct> <fct> <fct> <fct> <fct> <fct> <fct> <fct> <chr>
1 Alpha 1 1 1 1 3 4 6 7 6 7 9 0 9 Alp
2 Beta 1 0 0 1 NA NA NA NA NA NA NA NA NA Bet
您可以使用 splitstackshape::cSplit
:
library(dplyr)
splitstackshape::cSplit(df, 'y', sep = '', stripWhite = FALSE) %>%
mutate(across(starts_with('y'), factor)) %>%
rename_with(~names, starts_with('y'))
# x z A B C D
#1: Alpha Alp 1 1 1 1
#2: Beta Bet 1 0 0 1
我的目标是将一个由 1 和 0 组成的字符列拆分成它们自己的列。我希望新列的类型为“因素”。我找到了一种拆分列的好方法(使用 dplyr 的“mutate”和 reshape2 的“colsplit”),但未能找到一种有效的方法来使所有结果列的类型为“factor”。
这是我的问题的一个最小示例:
library(dplyr)
library(reshape2)
# Data frame to be processed
df = tribble(
~x, ~y, ~z,
"Alpha", "1111", "Alp",
"Beta", "1001", "Bet"
)
# Vector Containing Names for columns
names = c("A", "B", "C", "D")
df %>%
mutate_at("y", colsplit, names = names, pattern = "")
输出:
# A tibble: 2 x 3
x y$A $B $C $D z
<chr> <int> <int> <int> <int> <chr>
1 Alpha 1 1 1 1 Alp
2 Beta 1 0 0 1 Bet
此示例生成正确的 table,只是我希望新列成为因子(下游脚本需要)。我还希望新列不使用有关旧列的信息命名,我认为这是 colsplit
的一个特征——指的是 y$
和 $
部分。
目前,我唯一能使所有列成为因子的方法是手动编辑它们,这是相当低效的。
我试过的其他解决方案:
我也尝试使用 tidyverse 中的 separate
来解决这个问题,但无法正确划分。我不明白它使用的是什么正则表达式。例如,这段代码:
df %>%
separate("y", into = names, sep = "")
结果:
# A tibble: 2 x 6
x A B C D z
<chr> <chr> <chr> <chr> <chr> <chr>
1 Alpha "" 1 1 1 Alp
2 Beta "" 1 0 0 Bet
哪个似乎是在选择字符串之前的第一个空格?我不太清楚那是怎么回事。
此外,实际上,第 y
列中的字符串可以是不同的长度(但在正在处理的数据集中将保持一致的大小——例如,y 可以是 100 个字符长,并且它每行将有 100 长)。
这是使用 dplyr
& tidyr
library(dplyr)
library(tidyr)
# Create a names vector that dynamic base on length of y index from 1 to max length
# As "" feed to separate as separator so the first matched is an empty char
# for this case we add a column to be dropped later into the names list.
names <- c("drop", seq_len(max(sapply(df$y, nchar))))
df %>%
separate("y", into = names, sep = "", fill = "warn") %>%
mutate_if(.predicate = is.character, .funs = factor) %>%
select(-drop)
#> # A tibble: 2 x 6
#> x `1` `2` `3` `4` z
#> <fct> <fct> <fct> <fct> <fct> <fct>
#> 1 Alpha 1 1 1 1 Alp
#> 2 Beta 1 0 0 1 Bet
或另一种方法,仅将 names
中出现的列转换为因子
df %>%
separate("y", into = names, sep = "") %>%
mutate_at(vars(one_of(names)), .funs = factor) %>%
select(-drop)
#> # A tibble: 2 x 6
#> x `1` `2` `3` `4` z
#> <chr> <fct> <fct> <fct> <fct> <chr>
#> 1 Alpha 1 1 1 1 Alp
#> 2 Beta 1 0 0 1 Bet
由 reprex package (v2.0.0)
于 2021-05-15 创建我不太确定你的要求,但你可以做这样的事情(稍微改变你的 df,以表明不需要对 colnames 进行硬编码)
df = tribble(
~x, ~y, ~z,
"Alpha", "1111346767909", "Alp",
"Beta", "1001", "Bet"
)
# A tibble: 2 x 3
x y z
<chr> <chr> <chr>
1 Alpha 1111346767909 Alp
2 Beta 1001 Bet
df %>%
separate(y, into = paste0('y_', seq_len(1 + max(nchar(.$y)))-1), sep = '', fill = 'right' ) %>%
select(!ends_with('_0')) %>%
mutate(across(starts_with('y_'), factor))
# A tibble: 2 x 15
x y_1 y_2 y_3 y_4 y_5 y_6 y_7 y_8 y_9 y_10 y_11 y_12 y_13 z
<chr> <fct> <fct> <fct> <fct> <fct> <fct> <fct> <fct> <fct> <fct> <fct> <fct> <fct> <chr>
1 Alpha 1 1 1 1 3 4 6 7 6 7 9 0 9 Alp
2 Beta 1 0 0 1 NA NA NA NA NA NA NA NA NA Bet
您可以使用 splitstackshape::cSplit
:
library(dplyr)
splitstackshape::cSplit(df, 'y', sep = '', stripWhite = FALSE) %>%
mutate(across(starts_with('y'), factor)) %>%
rename_with(~names, starts_with('y'))
# x z A B C D
#1: Alpha Alp 1 1 1 1
#2: Beta Bet 1 0 0 1