You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

R语言逐行统计数据框值出现次数过慢,求高效优化方案

高效统计R语言数据框每行特定值出现次数的方法

嘿,我来帮你解决这个大数据量下的统计效率问题!先理清楚你的需求和当前的困境:

你的场景

你有一个类似这样的数据框:

# 输入数据框示例
df <- data.frame(
  a = c(1, 0, -1),
  b = c(1, -1, 0),
  c = c(0, -1, NA),
  d = c(-1, 1, NA),
  e = c(NA, NA, 1)
)

打印出来是这样的:

a  b  c  d  e
1 1  1  0 -1 NA
2 0 -1 -1  1 NA
3 -1 0 NA NA  1

你需要给每行统计-1、0、1和NA的出现次数,最终得到这样的结果:

a  b  c  d  e count.-1 count.0 count.1 count.NA
1 1  1  0 -1 NA        1       1       2        1
2 0 -1 -1  1 NA        2       1       1        1
3 -1 0 NA NA  1        0       1       2        2

你现在用的是purrr::by_row逐行处理的方法,代码如下:

library(dplyr)
library(purrr)

df = df %>% 
  by_row( ..f = function(x) { sum(is.na(x[1:8])) }, .to = "count_na", .collate = "cols" ) %>% 
  by_row( ..f = function(x) { sum(x[1:8] == 1, na.rm = T) }, .to = "count_positive", .collate = "cols" ) %>% 
  by_row( ..f = function(x) { sum(x[1:8] == -1, na.rm = T) }, .to = "count_negative", .collate = "cols" ) %>% 
  by_row( ..f = function(x) { sum(x[1:8] == 0, na.rm = T) }, .to = "count_neutral", .collate = "cols" )

但处理500万行数据时耗时超3小时,这显然是因为逐行循环的开销太大了,接下来给你两个高效的替代方案:

方案1:用dplyr的向量化rowSums(快速且易读)

rowSums是R原生的向量化操作,直接对整个列维度计算,完全避免了逐行循环的开销,速度会快很多:

library(dplyr)

# 统计所有列的情况
df_result <- df %>%
  mutate(
    count.-1 = rowSums(. == -1, na.rm = TRUE),
    count.0 = rowSums(. == 0, na.rm = TRUE),
    count.1 = rowSums(. == 1, na.rm = TRUE),
    count.NA = rowSums(is.na(.))
  )

# 如果只需要统计前8列(和你原代码一致),可以指定列范围
df_result <- df %>%
  mutate(
    count.-1 = rowSums(select(., 1:8) == -1, na.rm = TRUE),
    count.0 = rowSums(select(., 1:8) == 0, na.rm = TRUE),
    count.1 = rowSums(select(., 1:8) == 1, na.rm = TRUE),
    count.NA = rowSums(is.na(select(., 1:8)))
  )

方案2:用data.table(超大数据量的最优选择)

如果你的数据量真的达到500万行,data.table是更好的选择——它的底层是C语言实现的,操作效率比普通dplyr还要高一个量级:

library(data.table)

# 先把普通data.frame转成data.table
setDT(df)

# 统计所有列的情况
df_stats <- df[, .(
  count.-1 = rowSums(.SD == -1, na.rm = TRUE),
  count.0 = rowSums(.SD == 0, na.rm = TRUE),
  count.1 = rowSums(.SD == 1, na.rm = TRUE),
  count.NA = rowSums(is.na(.SD))
)]

# 合并原数据和统计结果
df_result <- cbind(df, df_stats)

# 如果只统计前8列,指定.SDcols参数
df_stats <- df[, .(
  count.-1 = rowSums(.SD == -1, na.rm = TRUE),
  count.0 = rowSums(.SD == 0, na.rm = TRUE),
  count.1 = rowSums(.SD == 1, na.rm = TRUE),
  count.NA = rowSums(is.na(.SD))
), .SDcols = 1:8]

df_result <- cbind(df, df_stats)

为什么原方法这么慢?

by_row本质是在做逐行循环,每一行都要单独调用一次函数,这种“循环+函数调用”的模式在R里是出了名的低效,尤其是数据量到百万级的时候,累计的开销会非常夸张。而上面的两种方案都是向量化操作,直接对整个数据集的列进行批量计算,没有逐行的额外开销,速度能提升几十甚至上百倍。

内容的提问来源于stack exchange,提问作者R.vW

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 07:24:36