将字符向量列子集化为多列
Subsetting a character vector column into multiple columns
我有以下问题:
colours = tribble(
~all,
c('blue','green', 'red', 'pink', 'yellow', 'gold', 'orange', 'ivory', 'brown', 'beige'),
c('green', 'red', 'pink', 'orange', 'ivory', 'beige')
)
我想根据颜色系列将颜色分成多列:Cool
、Warm
、Neutral
,每个系列一列。
我可以使用 mutate
与 map
和 str_subset
:
colours %>%
mutate(
'Cool' = map(all, ~str_subset(., '^(blue|green)$')),
'Warm' = map(all, ~str_subset(., '^(red|pink|yellow|gold|orange)$')),
'Neutral' = map(all, ~str_subset(., '^(ivory|brown|beige)$'))
)
# A tibble: 2 x 4
all Cool Warm Neutral
<list> <list> <list> <list>
1 <chr [10]> <chr [2]> <chr [5]> <chr [3]>
2 <chr [6]> <chr [1]> <chr [3]> <chr [2]>
但我想知道是否有更简洁的方法来实现相同的结果?我试过 tidyr::extract()
但似乎无法获得正则表达式右:
colours %>%
mutate(all = map(all, ~paste(., collapse = ' '))) %>%
extract(all, into = c('Cool', 'Warm', 'Neutral'),
regex = '(blue|green)|(red|pink|yellow|gold|orange)|(ivory|brown|beige)')
我猜这是不正确的,因为 OR 语句匹配每个组中的单个单词,而不是将字符串分成三个子字符串,每个子字符串包含每个组的所有匹配单词? Here is the demo。
我非常确信 extract
行不通,但它使用了正确的正则表达式。它实际上并不比您的第一个解决方案 "succinct" 多多少,但我认为它可能已经尽可能简洁了。 (如果你想缩短事情,考虑将你的颜色折叠成一个双元素字符向量,而不是一个带有列表列的数据框。)
您的正则表达式模式的问题是您对 |
的使用。您想要定位单词集合,而不是 "x OR y OR z",这是您的模式所做的,也是您每行只获得一个匹配项的原因。要创建可能匹配项的集合,请使用 []
。为 "zero or more" 个匹配项包含 *
。使用上面的示例数据:
library(tidyverse)
colours %>%
mutate(all = map(all, str_c, collapse = " ")) %>%
extract(all, c("cool", "warm", "neutral"),
"([blue green]*) ([red pink yellow gold orange]*) ([ivory brown beige]*)",
remove = F # Include the `all` column.
)
#### OUTPUT ####
# A tibble: 2 x 4
all cool warm neutral
<list> <chr> <chr> <chr>
1 <chr [1]> blue green red pink yellow gold orange ivory brown beige
2 <chr [1]> green red pink orange ivory beige
主要注意事项是 颜色类别 需要按正确的顺序排列,即字符串必须包含顺序为 cool
的颜色词组 → warm
→ neutral
。如果它们是随机的,它将不起作用。事实上,如果颜色词是随机的,我认为 extract
将不再有效,因为无法提取单个词然后将它们连接起来。您还会丢失列表中的列 - 如果这对您很重要。
如果无法保证顺序,或者可能缺少某些类别词,那么您可以执行以下操作。使用类别词的随机样本(请注意,我删除了列表列,以便您可以看到发生了什么):
col_rand <- tribble(
~all,
sample(c('blue','green', 'red', 'pink', 'yellow', 'gold', 'orange', 'ivory', 'brown', 'beige'), 5),
sample(c('green', 'red', 'pink', 'orange', 'ivory', 'beige'), 4)
) %>%
mutate(all = map(all, str_c, collapse = " ") %>% unlist())
#### OUTPUT ####
# A tibble: 2 x 1
all
<chr>
1 blue yellow red beige pink
2 ivory pink beige orange
并具有以下模式:
patts <- c(cool = "blue|green",
warm = "red|pink|yellow|gold|orange",
neutral = "ivory|brown|beige"
)
您可以执行类似以下操作,提取匹配项并将它们连接起来,或者 returns NA
如果没有匹配项:
library(magrittr)
unlist(col_rand$all) %>%
map_dfr(function(x) {str_extract_all(x, patts) %>%
map(function(x) ifelse(length(x) == 0,
NA,
str_c(x, collapse = " ")
)
) %>%
bind_cols()}) %>%
set_colnames(names(patts)) %>% bind_cols(col_rand, .)
#### OUTPUT ####
# A tibble: 2 x 4
all cool warm neutral
<chr> <chr> <chr> <chr>
1 blue yellow red beige pink blue yellow red pink beige
2 ivory pink beige orange NA pink orange ivory beige
Note that the magrittr
library is loaded for the set_colnames
. If you load magrittr
after tidyverse
/tidyr
you'll need to use tidyr::extract()
above because both libraries have an extract
function.
我有以下问题:
colours = tribble(
~all,
c('blue','green', 'red', 'pink', 'yellow', 'gold', 'orange', 'ivory', 'brown', 'beige'),
c('green', 'red', 'pink', 'orange', 'ivory', 'beige')
)
我想根据颜色系列将颜色分成多列:Cool
、Warm
、Neutral
,每个系列一列。
我可以使用 mutate
与 map
和 str_subset
:
colours %>%
mutate(
'Cool' = map(all, ~str_subset(., '^(blue|green)$')),
'Warm' = map(all, ~str_subset(., '^(red|pink|yellow|gold|orange)$')),
'Neutral' = map(all, ~str_subset(., '^(ivory|brown|beige)$'))
)
# A tibble: 2 x 4
all Cool Warm Neutral
<list> <list> <list> <list>
1 <chr [10]> <chr [2]> <chr [5]> <chr [3]>
2 <chr [6]> <chr [1]> <chr [3]> <chr [2]>
但我想知道是否有更简洁的方法来实现相同的结果?我试过 tidyr::extract()
但似乎无法获得正则表达式右:
colours %>%
mutate(all = map(all, ~paste(., collapse = ' '))) %>%
extract(all, into = c('Cool', 'Warm', 'Neutral'),
regex = '(blue|green)|(red|pink|yellow|gold|orange)|(ivory|brown|beige)')
我猜这是不正确的,因为 OR 语句匹配每个组中的单个单词,而不是将字符串分成三个子字符串,每个子字符串包含每个组的所有匹配单词? Here is the demo。
我非常确信 extract
行不通,但它使用了正确的正则表达式。它实际上并不比您的第一个解决方案 "succinct" 多多少,但我认为它可能已经尽可能简洁了。 (如果你想缩短事情,考虑将你的颜色折叠成一个双元素字符向量,而不是一个带有列表列的数据框。)
您的正则表达式模式的问题是您对 |
的使用。您想要定位单词集合,而不是 "x OR y OR z",这是您的模式所做的,也是您每行只获得一个匹配项的原因。要创建可能匹配项的集合,请使用 []
。为 "zero or more" 个匹配项包含 *
。使用上面的示例数据:
library(tidyverse)
colours %>%
mutate(all = map(all, str_c, collapse = " ")) %>%
extract(all, c("cool", "warm", "neutral"),
"([blue green]*) ([red pink yellow gold orange]*) ([ivory brown beige]*)",
remove = F # Include the `all` column.
)
#### OUTPUT ####
# A tibble: 2 x 4
all cool warm neutral
<list> <chr> <chr> <chr>
1 <chr [1]> blue green red pink yellow gold orange ivory brown beige
2 <chr [1]> green red pink orange ivory beige
主要注意事项是 颜色类别 需要按正确的顺序排列,即字符串必须包含顺序为 cool
的颜色词组 → warm
→ neutral
。如果它们是随机的,它将不起作用。事实上,如果颜色词是随机的,我认为 extract
将不再有效,因为无法提取单个词然后将它们连接起来。您还会丢失列表中的列 - 如果这对您很重要。
如果无法保证顺序,或者可能缺少某些类别词,那么您可以执行以下操作。使用类别词的随机样本(请注意,我删除了列表列,以便您可以看到发生了什么):
col_rand <- tribble(
~all,
sample(c('blue','green', 'red', 'pink', 'yellow', 'gold', 'orange', 'ivory', 'brown', 'beige'), 5),
sample(c('green', 'red', 'pink', 'orange', 'ivory', 'beige'), 4)
) %>%
mutate(all = map(all, str_c, collapse = " ") %>% unlist())
#### OUTPUT ####
# A tibble: 2 x 1
all
<chr>
1 blue yellow red beige pink
2 ivory pink beige orange
并具有以下模式:
patts <- c(cool = "blue|green",
warm = "red|pink|yellow|gold|orange",
neutral = "ivory|brown|beige"
)
您可以执行类似以下操作,提取匹配项并将它们连接起来,或者 returns NA
如果没有匹配项:
library(magrittr)
unlist(col_rand$all) %>%
map_dfr(function(x) {str_extract_all(x, patts) %>%
map(function(x) ifelse(length(x) == 0,
NA,
str_c(x, collapse = " ")
)
) %>%
bind_cols()}) %>%
set_colnames(names(patts)) %>% bind_cols(col_rand, .)
#### OUTPUT ####
# A tibble: 2 x 4
all cool warm neutral
<chr> <chr> <chr> <chr>
1 blue yellow red beige pink blue yellow red pink beige
2 ivory pink beige orange NA pink orange ivory beige
Note that the
magrittr
library is loaded for theset_colnames
. If you loadmagrittr
aftertidyverse
/tidyr
you'll need to usetidyr::extract()
above because both libraries have anextract
function.