【问题标题】:Extract pattern from string, strip text, convert to numeric and sum in R data.table?从字符串中提取模式,剥离文本,转换为数字并在 R data.table 中求和?
【发布时间】:2015-11-27 00:39:04
【问题描述】:

我有一个(10 万行)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))

有没有更简洁、计算更高效的方法来做到这一点?

【问题讨论】:

  • 您没有提供可重现的示例,所以这里是评论中的伪代码答案:) f = function(x) unlist(lapply(strsplit(x, "M"),[[,1L)) 然后dt[, .(col = f(col))],总和应该不是问题。
  • @jangorecki 编辑为可重现的示例。

标签: regex r data.table sapply


【解决方案1】:

您可以创建一个函数来获取字符串中所有字母 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 在 cmets 中的建议更改了正则表达式,以实现更有效的匹配。

【讨论】:

  • 使用str_match_all(x, "\\d+(?=M)") 将不再需要子集,并且将在中间matches 变量中存储更少的数据。
【解决方案2】:

这是一个简洁的方法。

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)

【讨论】:

    猜你喜欢
    • 2011-06-18
    • 1970-01-01
    • 2021-03-26
    • 1970-01-01
    • 2013-11-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多