如何在R中按组统计唯一列值并识别非连续年份组?
R实现数据集统计任务方案
首先还原你的数据集:
name = c("john", "john", "john", "alex","alex", "tim", "tim", "tim", "ralph", "ralph") year = c(2010, 2011, 2012, 2011, 2012, 2010, 2011, 2012, 2014, 2016) my_data = data.frame(name, year)
任务1:按年份集合分组统计数量
实现思路
先按name聚合对应年份,对每个name的年份排序后拼接成统一格式的字符串(解决年份顺序不同的分组识别问题),最后统计每个字符串的出现次数。
dplyr 实现代码
library(dplyr) my_data %>% group_by(name) %>% summarise(year_set = paste(sort(year), collapse = ", ")) %>% ungroup() %>% count(year_set, name = "count") %>% rename(year = year_set)
基础R 实现代码
# 按name聚合并生成排序后的年份字符串 agg <- aggregate(year ~ name, my_data, function(x) paste(sort(x), collapse = ", ")) # 统计每个年份集合的数量 result1 <- as.data.frame(table(agg$year)) colnames(result1) <- c("year", "count") print(result1)
运行后得到目标输出:
year count 1 2010, 2011, 2012 2 2 2011, 2012 1 3 2014, 2016 1
任务2:统计包含非连续年份的组的数量
实现思路
在任务1基础上,增加对每个name年份序列的连续性判断:计算排序后年份的差值,若存在差值不等于1的情况,说明该组有非连续年份。筛选出这类组后,再统计对应年份集合的数量。
dplyr 实现代码
library(dplyr) my_data %>% group_by(name) %>% summarise( year_set = paste(sort(year), collapse = ", "), has_gap = any(diff(sort(year)) != 1) ) %>% ungroup() %>% filter(has_gap) %>% count(year_set, name = "count") %>% rename(year = year_set)
基础R 实现代码
# 按name聚合,生成年份字符串并判断是否有非连续 agg <- aggregate(year ~ name, my_data, function(x) { sorted_x <- sort(x) list( year_set = paste(sorted_x, collapse = ", "), has_gap = any(diff(sorted_x) != 1) ) }) # 转换为数据框并筛选 agg_df <- do.call(rbind, agg$year) agg_df <- cbind(agg$name, agg_df) colnames(agg_df) <- c("name", "year", "has_gap") # 统计符合条件的组数量 result2 <- as.data.frame(table(subset(agg_df, has_gap)$year)) colnames(result2) <- c("year", "count") print(result2)
运行后得到目标输出:
year count 1 2014, 2016 1
关于确保(2011, 2012)与(2012, 2011)视为同一组的解决方法
核心操作是对每个name对应的年份先执行排序,再拼接成字符串。不管原始数据中年份的顺序如何,排序后生成的字符串都是完全一致的,因此会被识别为同一分组。上面所有代码都包含了sort(year)的步骤,可直接解决该问题。
针对旧版R的任务2解决方案
# 按name聚合年份列表 agg <- aggregate(year ~ name, my_data, c) # 筛选出年份存在非连续的组 agg <- agg$year[sapply(agg$year, function(y) any(diff(y) != 1))] # 将年份列表拼接成字符串并统计数量(若需兼容年份顺序问题,可改为paste(sort(y), collapse = ", ")) as.data.frame(table(sapply(agg, paste, collapse = ", ")))
解释:这段代码先通过aggregate按name聚合年份为列表,再用sapply检查每个年份列表的差值是否存在不等于1的情况(即存在非连续年份),筛选出这类列表后,拼接成字符串并统计出现次数。如果原始数据中同一name的年份顺序混乱,建议在paste前加上sort(y),确保同一年份集合不会因顺序被误判为不同组。
内容的提问来源于stack exchange,提问作者stats_noob
相关产品推荐
相关产品推荐

