dplyr与base R筛选奥运数据结果不一致问题求助
Hey there! Let's break down why your Base R code was misbehaving and fix it up properly.
1. 警告与行数差异的原因
你最初的Base R代码行:
medalwinners_baseR <- subset(olympics, Medal == c("Bronze", "Silver", "Gold"))
存在一个关键问题:==是逐元素匹配运算符,而非“检查值是否属于某个集合”的工具。当你用较长的向量(Medal列)和较短的向量(c("Bronze", "Silver", "Gold"))对比时,R会循环重复短向量来匹配长向量的长度,这意味着它的匹配逻辑是:
- 第1行:Medal == "Bronze"
- 第2行:Medal == "Silver"
- 第3行:Medal == "Gold"
- 第4行:Medal == "Bronze"(循环重复)
- ...以此类推
这种方式只会保留那些Medal值恰好符合循环位置的行,这就是为什么你得到的行数远少于dplyr版本(1651 vs 5000),同时触发了“longer object length is not a multiple”警告。
而你的dplyr代码使用grepl("Bronze|Silver|Gold", Medal),能正确检查每个Medal值是否属于这三者之一,不受位置影响。
2. 修正后的Base R代码
以下是完全匹配你dplyr工作流的修正版Base R代码:
步骤1:正确筛选奖牌获得者
# 用%in%替代==,检查值是否属于目标集合 medalwinners_baseR <- subset(olympics, Medal %in% c("Bronze", "Silver", "Gold"))
%in%才是这里的正确工具——它会逐个检查Medal列的元素是否存在于奖牌类型向量中,和你dplyr代码里的grepl作用完全一致。
步骤2:统计各队奖牌数(更简洁的Base R写法)
比起split() + sapply(nrow),我们可以用专门用于分组计数的table()函数:
medals_perteam_baseR <- table(medalwinners_baseR$Team) # 按奖牌数降序排序 medals_perteam_baseR <- sort(medals_perteam_baseR, decreasing = TRUE)
这会得到和你dplyr生成的medals_perteam完全一致的结果。
步骤3:筛选前10名国家的记录
topmedals_baseR <- medalwinners_baseR[medalwinners_baseR$Team %in% names(medals_perteam_baseR)[1:10], ]
现在你可以检查nrow(topmedals_baseR),它应该和dplyr版本的topmedals行数一致。
3. 附加:制作前10名奖牌榜柱状图(Base R)
既然你的目标是生成前10国家的柱状图,这里是对应的Base R代码:
# 提取前10名的奖牌数 top10_medals <- medals_perteam_baseR[1:10] # 创建带格式的柱状图 barplot(top10_medals, main = "奥运奖牌数Top10国家", xlab = "国家", ylab = "总奖牌数", col = "steelblue", las = 2, # 旋转x轴标签提升可读性 cex.names = 0.8) # 缩小标签尺寸避免重叠
验证
运行修正代码后,你可以通过以下代码确认和dplyr结果的一致性:
# 检查筛选后的奖牌获得者行数是否匹配 nrow(medalwinners) == nrow(medalwinners_baseR) # 检查前10名国家列表是否一致 all(names(medals_perteam)[1:10] == names(medals_perteam_baseR)[1:10])
两行代码都应该返回TRUE。
内容的提问来源于stack exchange,提问作者TvCasteren

