高效创建数据框新列:提取字符串中的最大值
高效提取字符串中的数值最大值并判断阈值
问题背景
有如下示例数据框:
country <- c('Australia', 'Italy', 'Peru', 'China') score <- c("0.091", "0.413,.", "-", "0.102,0.102,0.102,.,.,.,.,.,.,.,.") country_scores <- data.frame(country, score)
score列的每个条目为任意数量的逗号分隔值,或用-表示无数据。需要提取每个字符串中的数值最大值,并判断其是否符合特定阈值。
原使用的tidyverse方案在130万行、186列的数据框上运行极慢(至少8分钟),原代码如下(注:原代码存在笔误,已修正关键错误):
library(tidyverse) country_scores %>% mutate(scores = str_extract_all(score, '\\d+(\\.\\d+)?'), score_max = map_dbl(scores, ~max(as.numeric(.x), na.rm = TRUE)))
高效实现方案
方案1:data.table + stringi(大数据量最优选择)
data.table的列向量化操作结合stringi的快速字符串处理,能大幅降低大数据量下的运算耗时:
library(data.table) library(stringi) # 转换为data.table格式 setDT(country_scores) # 批量处理score列,计算最大值 country_scores[, score_max := { # 按逗号分割字符串 split_list <- stri_split_fixed(score, ",") # 遍历每个分割后的列表,转数值并取最大值(忽略NA) sapply(split_list, function(x) { nums <- as.numeric(x) max(nums, na.rm = TRUE) }) }] # 将无数据(score为"-")的结果替换为NA country_scores[score == "-", score_max := NA_real_]
方案2:Base R向量化优化
无需加载tidyverse,用Base R的向量化函数实现,性能优于原map系列方案:
# 定义单字符串处理函数 get_max_score <- function(s) { if (s == "-") return(NA_real_) # 分割字符串并转数值 parts <- strsplit(s, ",")[[1]] nums <- as.numeric(parts) # 过滤无效值后取最大值 nums <- nums[!is.na(nums)] if (length(nums) == 0) return(NA_real_) max(nums) } # 向量化应用到整个列 country_scores$score_max <- sapply(country_scores$score, get_max_score)
方案3:优化后的tidyverse实现
如果坚持使用tidyverse,可通过转长格式分组计算减少逐行操作的开销:
library(tidyverse) country_scores %>% # 先标记无数据条目 mutate(score = ifelse(score == "-", NA_character_, score)) %>% # 提取所有数值并展开为长格式 mutate(scores = str_extract_all(score, '\\d+(\\.\\d+)?')) %>% unnest(scores) %>% mutate(scores = as.numeric(scores)) %>% # 按分组计算最大值 group_by(country) %>% summarise(score_max = max(scores, na.rm = TRUE), .groups = "drop") %>% # 合并回原数据框并修正无效值 right_join(country_scores, by = "country") %>% mutate(score_max = ifelse(is.infinite(score_max), NA_real_, score_max))
性能说明
- data.table + stringi方案性能最优,因为data.table的列操作经过高度优化,stringi的字符串处理速度远快于stringr。
- 原方案的慢主要源于
map_dbl的逐行处理,在百万级行规模下,逐行操作的开销会被急剧放大。
内容的提问来源于stack exchange,提问作者Sky Scraper
相关产品推荐
相关产品推荐

