统计data.frame双变量组合出现次数,求Base R简洁实现方案
更简洁的Base R方法统计组合出现次数
嗨,很高兴看到你已经用嵌套循环实现了需求,不过Base R里确实有不少更简洁、易读的工具能搞定这个统计任务,下面给你分享几种常用思路:
方法一:利用table()+merge()实现左连接统计
这是最直观的方法,先统计h中所有组合的频数,再和g合并补全所有组合:
# 先给h的列改名,和g保持一致方便处理 h_named <- setNames(h, c("where", "what")) # 统计组合频数,转成数据框 counts <- as.data.frame(table(h_named), responseName = "days") # 左连接合并到g,保留g的所有行 g_updated <- merge(g[, c("where", "what")], counts, by = c("where", "what"), all.x = TRUE) # 将未出现组合的频数设为0 g_updated$days[is.na(g_updated$days)] <- 0 # 还原g原来的行顺序 g_updated <- g_updated[match(paste(g$where, g$what), paste(g_updated$where, g_updated$what)), ]
table()是Base R专门用于统计分类变量组合频数的工具,转成数据框后通过merge(..., all.x = TRUE)做左连接,能确保g的所有组合都被保留,最后补0并还原顺序就和你用循环得到的结果完全一致了。
方法二:用xtabs()生成交叉表后合并
xtabs()可以直接生成交叉频数表,用法和table()类似,适合二维分类变量的统计:
h_named <- setNames(h, c("where", "what")) # 生成交叉频数表 freq_table <- xtabs(~ where + what, data = h_named) # 转成数据框 freq_df <- as.data.frame(freq_table, responseName = "days") # 合并并补0 g_updated <- merge(g[, 1:2], freq_df, by = c("where", "what"), all.x = TRUE) g_updated$days[is.na(g_updated$days)] <- 0 # 还原原顺序 g_updated <- g_updated[match(paste(g$where, g$what), paste(g_updated$where, g_updated$what)), ]
方法三:一行式赋值(最紧凑)
利用match()匹配组合字符串,直接给g$days赋值,代码更精简:
h_named <- setNames(h, c("where", "what")) # 匹配组合并提取频数,未匹配到的设为0 g$days <- table(h_named)[match(paste(g$where, g$what), rownames(table(h_named)))] g$days[is.na(g$days)] <- 0
table(h_named)的行名是"where.what"格式的字符串,我们用paste(g$where, g$what)生成相同格式的字符串,通过match()找到每个组合在频数表中的位置,直接提取对应数值,最后把NA替换为0即可。
为什么这些方法更好?
- 效率更高:都是向量化操作,相比嵌套循环,当
h的行数很大时,速度会快很多; - 可读性更强:代码逻辑清晰,一眼就能看出是在做组合频数统计,不需要理解循环里的逐行判断;
- 可维护性好:后续如果要扩展变量,只需要修改分类变量的参数,不需要调整循环结构。
内容的提问来源于stack exchange,提问作者vaettchen
相关产品推荐
相关产品推荐

