在R中基于Lookup Table生成殖民存在虚拟变量报错求助
问题分析与修复方案
错误原因
你遇到的missing value where TRUE/FALSE needed错误,核心有两个问题:
- 殖民状态匹配错误:原代码中
colonies_df[[paste0("col.", empire, ".", year)]]直接取整列数据,没有根据当前行的国家匹配colonies_df中对应的行,导致用整列值和单个组织的存在状态做逻辑判断,出现长度不匹配或NA。 - 缺失值/无匹配处理缺失:当
alldata中某行的国家没有对应的国家_年份列,或colonies_df中找不到对应国家的行时,会返回NA,导致if条件无法得到明确的TRUE/FALSE结果。
修复方案
方案1:修正原函数逻辑(保留循环写法)
修改create_col_presence函数,确保匹配对应国家的殖民状态,并处理NA和无匹配的情况:
create_col_presence <- function(row, colonies_df, empire, year) { country <- row$country # 找到colonies_df中对应国家的行 colony_match <- colonies_df[colonies_df$country == country, ] # 无匹配国家直接返回0 if (nrow(colony_match) == 0) { return(0) } # 获取组织存在状态和殖民归属状态 org_present <- row[[paste0(country, "_", year)]] colony_status <- colony_match[[paste0("col.", empire, ".", year)]] # 仅当两个状态都为1且无NA时返回1,否则返回0 if (!is.na(org_present) && org_present == 1 && !is.na(colony_status) && colony_status == 1) { return(1) } else { return(0) } } # 循环生成新列(用vapply替代sapply,类型更稳定) for (empire in c("belgium", "britain", "france", "germany", "italy", "netherlands", "portugal", "spain")) { for (year in c(1954, 1970, 1988, 2003, 2017)) { new_col_name <- paste0("colpresence_", empire, "_", year) alldata[[new_col_name]] <- vapply(1:nrow(alldata), function(i) { create_col_presence(alldata[i, ], colonies_df, empire, year) }, FUN.VALUE = integer(1)) } }
方案2:用tidyverse向量化处理(更高效推荐)
通过转换为长格式数据匹配,避免逐行循环,效率更高且更易维护:
library(tidyverse) # 1. 将alldata转为长格式:组织-国家-年份-存在状态 alldata_long <- alldata %>% pivot_longer( cols = matches("^[A-Za-z]+_[0-9]{4}$"), names_to = c("country", "year"), names_sep = "_", values_to = "org_present", values_drop_na = FALSE ) %>% mutate(year = as.integer(year)) # 2. 将colonies_df转为长格式:国家-年份-殖民帝国归属 colonies_long <- colonies_df %>% pivot_longer( cols = matches("^col\\.[a-z]+\\.[0-9]{4}$"), names_to = c(NA, "empire", "year"), names_sep = "\\.", values_to = "colony_of_empire", values_drop_na = FALSE ) %>% mutate(year = as.integer(year)) # 3. 合并数据并计算colpresence combined <- alldata_long %>% left_join(colonies_long, by = c("country", "year")) %>% mutate( colpresence = ifelse(org_present == 1 & colony_of_empire == 1, 1, 0), colpresence_col = paste0("colpresence_", empire, "_", year) ) # 4. 将结果转回宽格式并合并回原alldata colpresence_wide <- combined %>% select(-country, -year, -org_present, -empire, -colony_of_empire) %>% pivot_wider( names_from = colpresence_col, values_from = colpresence, values_fill = 0 ) alldata <- alldata %>% bind_cols(colpresence_wide)
内容的提问来源于stack exchange,提问作者Agata T
相关产品推荐
相关产品推荐

