使用 dplyr mutate 和现有列的子字符串创建新列
Create new column with dplyr mutate and substring of existing column
我有一个包含一列字符串的数据框,我想将这些字符串的子字符串提取到一个新列中。
下面是一些示例代码和数据,显示我想在 id
列中的最后一个下划线字符之后获取字符串,以便创建 new_id
列。
id
列条目始终有 2 个下划线字符,它始终是我想要的最后一个子字符串。
df = data.frame( id = I(c("abcd_123_ABC","abc_5234_NHYK")), x = c(1.0,2.0) )
require(dplyr)
df = df %>% dplyr::mutate(new_id = strsplit(id, split="_")[[1]][3])
我原以为 strsplit 会依次作用于每一行。
但是,new_id
列每行仅包含 ABC
,而我希望第 1 行包含 ABC
,第 2 行包含 NHYK
。你知道吗为什么会失败以及如何实现我想要的?
这是使用 strsplit
的一种通用方式来完成您要查找的内容。
library(dplyr)
df = data.frame( id = I(c("abcd_123_ABC","abc_5234_NHYK")), x = c(1.0,2.0) )
temp <- seq(from=3, by=3, length.out = length(df))
dfn <- df %>% dplyr::mutate(new_id = unlist(strsplit(id, split="_"))[temp])
> dfn
id x new_id
1 abcd_123_ABC 1 ABC
2 abc_5234_NHYK 2 NHYK
您可以使用 stringr::str_extract
:
library(stringr)
df %>%
dplyr::mutate(new_id = str_extract(id, "[^_]+$"))
#> id x new_id
#> 1 abcd_123_ABC 1 ABC
#> 2 abc_5234_NHYK 2 NHYK
正则表达式表示,匹配 不是 _
的一个或多个 (+
) 个字符(取反 [^ ]
),后跟字符串结尾 ($
).
使用dplyr::rowwise
:
df %>% dplyr::rowwise() %>% dplyr::mutate(new_id = strsplit(id, split="_")[[1]][3])
此处讨论了其他备选方案:
http://www.expressivecode.org/2014/12/17/mutating-using-functions-in-dplyr/
没有正则表达式并保持 tidyverse
风格的替代方法是使用 tidyr::separate()
。请注意,这确实会默认删除输入列(remove=FALSE
以防止它)。
## using your example data
df = data.frame( id = I(c("abcd_123_ABC","abc_5234_NHYK")), x = c(1.0,2.0) )
## separate knowing you will have three components
df %>% separate(id, c("first", "second", "new_id"), sep = "_") %>% select(-first, -second)
## returns
new_id x
1 ABC 1
2 NHYK 2
这可以使用 str_split
通过指定 simplify
参数来完成。
Simplify 取消列出拆分字符串并允许使用索引选择元素。在这种情况下总是有 2x 个“_”,我们总是可以取第三个元素。
# Create df
df = data.frame( id = I(c("abcd_123_ABC","abc_5234_NHYK")), x = c(1.0,2.0) )
# Create new_id using dplyr only
df <- df %>%
mutate(new_id = str_split(id, "_", simplify = TRUE)[ , 3])
我有一个包含一列字符串的数据框,我想将这些字符串的子字符串提取到一个新列中。
下面是一些示例代码和数据,显示我想在 id
列中的最后一个下划线字符之后获取字符串,以便创建 new_id
列。
id
列条目始终有 2 个下划线字符,它始终是我想要的最后一个子字符串。
df = data.frame( id = I(c("abcd_123_ABC","abc_5234_NHYK")), x = c(1.0,2.0) )
require(dplyr)
df = df %>% dplyr::mutate(new_id = strsplit(id, split="_")[[1]][3])
我原以为 strsplit 会依次作用于每一行。
但是,new_id
列每行仅包含 ABC
,而我希望第 1 行包含 ABC
,第 2 行包含 NHYK
。你知道吗为什么会失败以及如何实现我想要的?
这是使用 strsplit
的一种通用方式来完成您要查找的内容。
library(dplyr)
df = data.frame( id = I(c("abcd_123_ABC","abc_5234_NHYK")), x = c(1.0,2.0) )
temp <- seq(from=3, by=3, length.out = length(df))
dfn <- df %>% dplyr::mutate(new_id = unlist(strsplit(id, split="_"))[temp])
> dfn
id x new_id
1 abcd_123_ABC 1 ABC
2 abc_5234_NHYK 2 NHYK
您可以使用 stringr::str_extract
:
library(stringr)
df %>%
dplyr::mutate(new_id = str_extract(id, "[^_]+$"))
#> id x new_id
#> 1 abcd_123_ABC 1 ABC
#> 2 abc_5234_NHYK 2 NHYK
正则表达式表示,匹配 不是 _
的一个或多个 (+
) 个字符(取反 [^ ]
),后跟字符串结尾 ($
).
使用dplyr::rowwise
:
df %>% dplyr::rowwise() %>% dplyr::mutate(new_id = strsplit(id, split="_")[[1]][3])
此处讨论了其他备选方案:
http://www.expressivecode.org/2014/12/17/mutating-using-functions-in-dplyr/
没有正则表达式并保持 tidyverse
风格的替代方法是使用 tidyr::separate()
。请注意,这确实会默认删除输入列(remove=FALSE
以防止它)。
## using your example data
df = data.frame( id = I(c("abcd_123_ABC","abc_5234_NHYK")), x = c(1.0,2.0) )
## separate knowing you will have three components
df %>% separate(id, c("first", "second", "new_id"), sep = "_") %>% select(-first, -second)
## returns
new_id x
1 ABC 1
2 NHYK 2
这可以使用 str_split
通过指定 simplify
参数来完成。
Simplify 取消列出拆分字符串并允许使用索引选择元素。在这种情况下总是有 2x 个“_”,我们总是可以取第三个元素。
# Create df
df = data.frame( id = I(c("abcd_123_ABC","abc_5234_NHYK")), x = c(1.0,2.0) )
# Create new_id using dplyr only
df <- df %>%
mutate(new_id = str_split(id, "_", simplify = TRUE)[ , 3])