从字符串中提取模式,剥离文本,转换为数字并在 R data.table 中求和?
Extract pattern from string, strip text, convert to numeric and sum in R data.table?
我有一个(100k 行)data.table mydata,其中一列如下所示:
library(data.table)
library(stringr)
mdata <- data.table(A = c("17M1I26M570M20S1M", "17M1I260M570M20S1M"))
我如何有效地 - 最好是在 1 行代码中 - 提取 M 之前的所有数字(它们的长度可以是不同的数字),将它们转换为数字并求出它们的总和。
我已经设法通过 3 轮 sapply 函数做到了这一点,并创建了一些我不需要的附加列:
mdata$c <- sapply(mydata[, A], function(x) unlist(str_extract_all(x, "\d+M")))
mdata$c2 <-sapply(mydata[, c], function(x) unlist(as.numeric(gsub( "M", "",x))))
mdata$c3 <- sapply(mydata[,c2], function(x) sum(x))
是否有更简洁、计算效率更高的方法来做到这一点?
您可以创建一个函数来获取出现在字符串中所有字母 M 实例之前的数字的总和,然后在您的 data.table
.
中创建一个列
示例代码如下:
# Load data.table and stringr packages
library(data.table)
library(stringr)
# Data provided in the question
mydata <- data.table(A = c("17M1I26M570M20S1M", "17M1I260M570M20S1M"))
# Function to grab the sum of numbers before the letter M in a string
sum_before_m <- function(x) {
# Grab all numbers that appear before M
matches <- str_match_all(x, "\d+(?=M)")
# Grab the matches column in the list, transform to numeric, then sum
sapply(matches, function(y) sum(as.numeric(y)))
}
# Run the function for the column A
mydata[, c := sum_before_m(A)]
mydata
# A c
# 1: 17M1I26M570M20S1M 614
# 2: 17M1I260M570M20S1M 848
编辑: 使用@thelatemail 在评论中的建议更改了正则表达式以提高匹配效率。
这是一个简洁的方法。
library(dplyr)
library(tidyr)
library(stringi)
library(rex)
regex_1 =
rex(capture(digits),
capture(letter) )
data =
data_frame(
a = c("17M1I26M570M20S1M",
"17M1I260M570M20S1M") )
key =
data %>%
select(a) %>%
distinct %>%
mutate(match_list =
a %>%
stri_extract_all_regex(regex_1) ) %>%
unnest(match_list) %>%
extract(match_list,
c("number", "letter"),
regex_1) %>%
group_by(a) %>%
mutate(order = 1:n(),
number = as.numeric(number))
key %>%
group_by(a) %>%
summarize(total = sum(number)) %>%
right_join(data)
我有一个(100k 行)data.table mydata,其中一列如下所示:
library(data.table)
library(stringr)
mdata <- data.table(A = c("17M1I26M570M20S1M", "17M1I260M570M20S1M"))
我如何有效地 - 最好是在 1 行代码中 - 提取 M 之前的所有数字(它们的长度可以是不同的数字),将它们转换为数字并求出它们的总和。
我已经设法通过 3 轮 sapply 函数做到了这一点,并创建了一些我不需要的附加列:
mdata$c <- sapply(mydata[, A], function(x) unlist(str_extract_all(x, "\d+M")))
mdata$c2 <-sapply(mydata[, c], function(x) unlist(as.numeric(gsub( "M", "",x))))
mdata$c3 <- sapply(mydata[,c2], function(x) sum(x))
是否有更简洁、计算效率更高的方法来做到这一点?
您可以创建一个函数来获取出现在字符串中所有字母 M 实例之前的数字的总和,然后在您的 data.table
.
示例代码如下:
# Load data.table and stringr packages
library(data.table)
library(stringr)
# Data provided in the question
mydata <- data.table(A = c("17M1I26M570M20S1M", "17M1I260M570M20S1M"))
# Function to grab the sum of numbers before the letter M in a string
sum_before_m <- function(x) {
# Grab all numbers that appear before M
matches <- str_match_all(x, "\d+(?=M)")
# Grab the matches column in the list, transform to numeric, then sum
sapply(matches, function(y) sum(as.numeric(y)))
}
# Run the function for the column A
mydata[, c := sum_before_m(A)]
mydata
# A c
# 1: 17M1I26M570M20S1M 614
# 2: 17M1I260M570M20S1M 848
编辑: 使用@thelatemail 在评论中的建议更改了正则表达式以提高匹配效率。
这是一个简洁的方法。
library(dplyr)
library(tidyr)
library(stringi)
library(rex)
regex_1 =
rex(capture(digits),
capture(letter) )
data =
data_frame(
a = c("17M1I26M570M20S1M",
"17M1I260M570M20S1M") )
key =
data %>%
select(a) %>%
distinct %>%
mutate(match_list =
a %>%
stri_extract_all_regex(regex_1) ) %>%
unnest(match_list) %>%
extract(match_list,
c("number", "letter"),
regex_1) %>%
group_by(a) %>%
mutate(order = 1:n(),
number = as.numeric(number))
key %>%
group_by(a) %>%
summarize(total = sum(number)) %>%
right_join(data)