如何从非对称数据生成行列名称一致的对称DataFrame
问题描述
我有如下格式的数据:
country1 country2 value 1 GER USA 3 2 AUS AUS 6 3 YUG YUG 4 4 SIN GER 3
生成该数据的示例代码:
country1 <- c("GER", "AUS", "YUG", "SIN") country2 <- c("USA", "AUS", "YUG", "GER") value <- c(3, 6, 4, 3) mydf <- as.data.frame(cbind(country1, country2, value))
其中USA仅出现在country2列,SIN仅出现在country1列。
我希望创建一个交叉表,让country1和country2中的所有国家同时作为行和列。尝试了以下代码但无法解决问题:
mydf$country1 <- as.factor(mydf$country1) mydf$country2 <- as.factor(mydf$country2) mydf$value <- as.numeric(mydf$value) testtable <- as.data.frame.matrix(xtabs(value ~ mydf$country1 + mydf$country2, mydf))
该代码返回的结果中,SIN仅作为行存在,USA仅作为列存在:
AUS GER USA YUG AUS 6 0 0 0 GER 0 0 3 0 SIN 0 3 0 0 YUG 0 0 0 4
请问如何得到行列名称完全一致的对称DataFrame?
解决方案
问题根源在于country1和country2转为因子时,各自的水平集合不包含对方列里的国家。要实现行列名称完全一致,需要先统一两列的因子水平,把所有出现过的国家都纳入其中。
步骤1:统一因子水平并生成完整交叉表
# 提取所有出现过的唯一国家 all_countries <- unique(c(as.character(mydf$country1), as.character(mydf$country2))) # 将country1和country2转为因子,使用统一的水平集合 mydf$country1 <- factor(mydf$country1, levels = all_countries) mydf$country2 <- factor(mydf$country2, levels = all_countries) # 注意:cbind生成的value是字符型,需先转数值型 mydf$value <- as.numeric(as.character(mydf$value)) # 生成交叉表并转为数据框 testtable <- as.data.frame.matrix(xtabs(value ~ country1 + country2, data = mydf))
运行后得到的完整交叉表:
AUS GER SIN USA YUG AUS 6 0 0 0 0 GER 0 0 0 3 0 SIN 0 3 0 0 0 USA 0 0 0 0 0 YUG 0 0 0 0 4
步骤2:生成对称DataFrame(可选)
如果需要让表格对称(例如把SIN→GER的数值同步到GER→SIN的位置),可以添加以下代码:
# 生成对称矩阵 sym_table <- testtable + t(testtable) # 修正对角线值(避免自身到自身的数值被重复计算) diag(sym_table) <- diag(testtable)
最终对称结果:
AUS GER SIN USA YUG AUS 6 0 0 0 0 GER 0 0 3 3 0 SIN 0 3 0 0 0 USA 0 3 0 0 0 YUG 0 0 0 0 4
内容的提问来源于stack exchange,提问作者craszer
相关产品推荐
相关产品推荐

