R语言中高效标记首次出现模式的所有年份行的方法
问题与解决方案
问题描述
现有如下R数据集:
year = c("2000", "2000", "2000", "2002", "2000", "2002", "2007") id = c("X", "X", "X", "X", "Z", "Z", "Z") product = c("apple", "orange", "orange", "orange", "cake", "cake", "bacon") market = c("CHN", "USA", "USA", "USA", "SPA", "CHL", "CHL") df = data.frame(year, id, product, market)
需要创建三个变量:
- FPFM:若当前行是
id-产品-市场组合首次出现的年份,取值为1;否则为0 - FP:若当前行是
id-产品组合首次出现的年份,取值为1;否则为0 - FM:若当前行是
id-市场组合首次出现的年份,取值为1;否则为0
期望输出数据集:
year = c("2000", "2000", "2000", "2002", "2000", "2002", "2007") id = c("X", "X", "X", "X", "Z", "Z", "Z") product = c("apple", "orange", "orange", "orange", "cake", "cake", "bacon") market = c("CHN", "USA", "USA", "USA", "SPA", "CHL", "CHL") FPFM = c(1, 1, 1, 0, 1, 1, 1) FP = c(1, 1, 1, 0, 1, 0, 1) FM = c(1, 1, 1, 0, 1, 1, 0) df_desired = data.frame(year, id, product, market, FPFM, FP, FM)
用户尝试的代码仅标记每组的第一行,无法将同一首次年份的所有行标记为1,且希望避免多次汇总后连接的低效方法:
df_new <- df %>% arrange(id, year) %>% group_by(id, product, market) %>% mutate(FPFM = row_number(year) == 1) %>% as.data.frame() %>% group_by(id, product) %>% mutate(FP = row_number(year) == 1) %>% as.data.frame() %>% group_by(id, market) %>% mutate(FM = row_number(year) == 1) %>% as.data.frame()
高效解决方案
核心思路是:针对每个分组,找到该组首次出现的年份(即分组内最小的年份),判断当前行的年份是否等于这个最小年份,将结果转为1/0即可。全程在dplyr管道内完成,无需拆分或连接数据:
library(dplyr) df_result <- df %>% # 先将year转为数值型,确保年份比较准确(原字符型也可比较,转数值更稳妥) mutate(year = as.numeric(year)) %>% # 按id-产品-市场分组,标记首次出现年份的所有行 group_by(id, product, market) %>% mutate(FPFM = as.integer(year == min(year))) %>% # 按id-产品分组,标记首次出现年份的所有行 group_by(id, product) %>% mutate(FP = as.integer(year == min(year))) %>% # 按id-市场分组,标记首次出现年份的所有行 group_by(id, market) %>% mutate(FM = as.integer(year == min(year))) %>% # 取消分组,恢复为普通数据框 ungroup() %>% # 把year转回字符型(如果需要和原数据格式一致) mutate(year = as.character(year))
代码说明
year == min(year):判断当前行的年份是否是该分组的最小年份(即首次出现的年份),返回布尔值TRUE/FALSEas.integer():将布尔值转为1/0,符合需求的数值格式- 全程使用管道操作,无需拆分或连接数据,处理大数据集时效率更高
验证结果:输出的df_result与期望的df_desired完全一致。
内容的提问来源于stack exchange,提问作者vog
相关产品推荐
相关产品推荐

