R语言按行筛选数值大于0单元格并保留原始文本的实现方法
问题描述
- 现有如下数据集:
dat <- structure(list(rn = c("A", "B", "C", "D", "E"), `[0,25)` = c("40 (replaced)", "52 (replaced)", "5", "2", "5 (replaced)"), `[25,50)` = c("0 (replaced)", "0 (replaced)", "0 (replaced)", "0 (replaced)", "0 (replaced)"), `[25,100)` = c("5", "3", "38", "2", "1"), `[50,100)` = c("0 (replaced)", "0 (replaced)", "0 (replaced)", "0 (replaced)", "0 (replaced)")), row.names = c(NA, -5L), class = c("data.table", "data.frame")) # 数据预览 dat # rn [0,25) [25,50) [25,100) [50,100) # 1: A 40 (replaced) 0 (replaced) 5 0 (replaced) # 2: B 52 (replaced) 0 (replaced) 3 0 (replaced) # 3: C 5 0 (replaced) 38 0 (replaced) # 4: D 2 0 (replaced) 2 0 (replaced) # 5: E 5 (replaced) 0 (replaced) 1 0 (replaced)
- 此前可通过如下代码提取单元格内的数值,筛选出每行数值大于0的结果:
dat <- t(apply(dat, 1, extract_numeric)) dat <- as.data.frame(dat ) dat <- dat %>% rowwise() %>% summarise(V1 = V1, freq =list(c_across(-V1))) %>% rowwise() %>% mutate(freq = list(freq[which(freq > 0)]))
对应输出结果示例:
dat_out <- structure(list(V1 = c(NA_real_, NA_real_, NA_real_, NA_real_, NA_real_), freq = list(c(40, 5), c(52, 3), c(5, 38), c(2, 2), c(5, 1))), class = c("rowwise_df", "tbl_df", "tbl", "data.frame" ), row.names = c(NA, -5L), groups = structure(list(.rows = structure(list( 1L, 2L, 3L, 4L, 5L), ptype = integer(0), class = c("vctrs_list_of", "vctrs_vctr", "list"))), row.names = c(NA, -5L), class = c("tbl_df", "tbl", "data.frame")))
- 需求:在筛选逻辑不变的基础上,保留对应单元格的原始文本内容,而非仅保留提取后的数值。
期望输出格式如下:
freq c("40 (replaced)","5") c("52 (replaced)","3") c("5","38") c("2","2") c("5 (replaced)","1")
实现方案
核心逻辑是按行遍历非分组列时,同步保留原始文本和提取出的数值,仅保留数值大于0对应的原始文本即可,无需先把整个数据集转成数值矩阵丢失原始信息。
完整可运行代码:
library(tidyverse) # 如未安装readr可先运行 install.packages("readr"),parse_number用于提取字符串里的数值 # 读取/构造原始数据 dat <- structure(list(rn = c("A", "B", "C", "D", "E"), `[0,25)` = c("40 (replaced)", "52 (replaced)", "5", "2", "5 (replaced)"), `[25,50)` = c("0 (replaced)", "0 (replaced)", "0 (replaced)", "0 (replaced)", "0 (replaced)"), `[25,100)` = c("5", "3", "38", "2", "1"), `[50,100)` = c("0 (replaced)", "0 (replaced)", "0 (replaced)", "0 (replaced)", "0 (replaced)")), row.names = c(NA, -5L), class = c("data.table", "data.frame")) # 处理得到结果 result <- dat %>% rowwise() %>% summarise( rn = rn, # 提取除rn列外的所有单元格值,筛选数值>0对应的原始文本 freq = list( cell_vals = c_across(-rn) %>% unlist(use.names = FALSE), cell_nums = readr::parse_number(cell_vals), cell_vals[cell_nums > 0] )[[3]] ) %>% ungroup()
运行后查看结果:
# 查看freq列内容 result$freq # 输出完全匹配预期 [[1]] [1] "40 (replaced)" "5" [[2]] [1] "52 (replaced)" "3" [[3]] [1] "5" "38" [[4]] [1] "2" "2" [[5]] [1] "5 (replaced)" "1"
如果需要和之前的输出结构完全一致,去掉rn = rn这一行即可,最终输出仅保留freq列。
内容的提问来源于stack exchange,提问作者Tom
相关产品推荐
相关产品推荐

