我遇到一个问题,我试图从包含文本和数字的字符串中提取数字,然后创建两个新列来显示数字的最小值和最大值。
例如,我有一列和一串数据,像这样:
Text
Section 12345.01 to section 12345.02
我想从“文本”列中的数据创建两个新列,如下所示:
Min Max
12345.01 12345.02
我在regex中使用dplyr和stringr,但是regex仅提取模式的第一个匹配项(第一个数字)。
df%>%dplyr::mutate(SectionNum = stringr::str_extract(Text, "\\d+.\\d+"))
如果我尝试使用stringr::str_extract_all
函数。似乎提取了两种模式的出现,但它在小标题中创建了一个列表,我发现这是一个真正的麻烦。因此,我停留在第一步,只是尝试将数字放入自己的栏中。
有人可以推荐最有效的方法吗?理想情况下,我想从字符串中提取数字,将其转换为数字as.numeric
,然后运行min()
和max()
函数。
答案 0 :(得分:3)
使用extract
中的tidyr
。 extract
将每个正则表达式捕获组转换为自己的列。 convert = TRUE
的方便之处在于它可以将结果列强制为最佳格式。如果我们想保留原始列,可以使用remove = FALSE
。最后一个mutate
是可选的,以确保提取的第一个数字确实是最小值:
library(tidyr)
library(purrr)
df %>%
extract(Text, c("Min", "Max"), "([\\d.]+)[^\\d.]+([\\d.]+)", convert = TRUE) %>%
mutate(Min = pmap_dbl(., min),
Max = pmap_dbl(., max))
输出:
Min Max
1 12345.02 12345.03
数据:
df <- structure(list(Text = structure(1L, .Label = "Section 12345.03 to section 12345.02", class = "factor")), class = "data.frame", row.names = c(NA,
-1L), .Names = "Text")
答案 1 :(得分:3)
使用其他tidyverse
工具,您可以通过unnest
列出列表列并使用group_by
和summarise
语义(更多{{1} }),或者您可以按原样处理list-col并使用dplyr
从每一行中提取最大值和最小值(更多map_dbl
方式)。我的基准测试purrr
比map_dbl
和unnest
快7倍,比dplyr
快15%,尽管这只是一行。
extract
由reprex package(v0.2.0)于2018-09-24创建。
答案 2 :(得分:1)
已经有答案说明如何按照问题中的要求完成最终目标,但是只是为了解决如何使用stringr
包找到第一个或第二个比赛的问题,您可以使用str_match
函数,并通过参考str_match
列指定您感兴趣的特定匹配项。
library(stringr)
Text <- "Section 12345.01 to section 12345.02"
str_match(Text, "^[^0-9.]*([0-9.]*)[^0-9.]*([0-9.]*)[^0-9.]*$")[2]
#> [1] "12345.01"
str_match(Text, "^[^0-9.]*([0-9.]*)[^0-9.]*([0-9.]*)[^0-9.]*$")[3]
#> [1] "12345.02"
由reprex package(v0.2.0)于2018-09-24创建。