我有一个(100k行)data.table mydata,其中一列看起来像这样:
library(data.table)
library(stringr)
mdata <- data.table(A = c("17M1I26M570M20S1M", "17M1I260M570M20S1M"))
我如何有效 - 最好是在一行代码中 - 拉出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))
是否有更清洁,计算更有效的方法来做到这一点?
答案 0 :(得分:3)
您可以创建一个函数来获取字符串中字母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的建议更改了正则表达式,以便更有效地进行匹配。
答案 1 :(得分:0)
这是一种整洁的方式。
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)