如何对矩阵各列应用自定义函数?附普查区聚合街区收入计算需求
看起来你是要把普查区的分组收入数据汇总到街区层面,计算每个街区的家庭收入中位数对吧?这种分组数据的中位数计算得用加权中位数的思路,我来一步步帮你搞定。
首先先把你给出的数据整理清楚(注意看起来有个笔误,1500-19999应该是15000-19999吧?我后面会按修正后的逻辑处理):
# 模拟你的原始数据框(补全了部分未写完的数值) inc_df <- data.frame( Income_Interval = c("2500-9999", "10000-14999", "15000-19999", "20000-24999", "25000-29999", "30000-34999", "35000-39999"), `San Francisco` = c(22457, 20708, 12701, 12106, 10129, 10310, 9028), `Bayview Hunters Point` = c(1057, 920, 626, 491, 554, 338, 383), `Bernal Heights` = c(287, 288, 145, 285, 238, 257, 180), `Castro/Upper Market` = c(329, 463, 148, 160, 328, 179, 150), `Chinatown` = c(1059, 1327, 867, 689, 167, 289, 120) )
步骤1:处理收入区间,计算每个区间的中点
分组数据的中位数需要用区间中点作为代表值,我们可以写个小函数提取区间上下限并计算中点:
# 提取收入区间中点的函数 get_midpoint <- function(interval) { bounds <- as.numeric(strsplit(gsub(",", "", interval), "-")[[1]]) (bounds[1] + bounds[2]) / 2 } # 给数据框添加中点列 inc_df$Income_Midpoint <- sapply(inc_df$Income_Interval, get_midpoint)
步骤2:转换为长格式(tidy data)
宽格式数据不方便按街区分组计算,转成长格式更易操作:
library(tidyr) library(dplyr) inc_long <- inc_df %>% pivot_longer( cols = -c(Income_Interval, Income_Midpoint), names_to = "Neighborhood", values_to = "Household_Count" )
步骤3:计算每个街区的加权中位数
中位数的位置是总家庭数的一半,我们需要找到累计家庭数超过该位置的区间,再用线性插值计算精确中位数:
neighborhood_median <- inc_long %>% group_by(Neighborhood) %>% arrange(Income_Midpoint) %>% mutate( Cumulative_Count = cumsum(Household_Count), Total_Households = sum(Household_Count), Median_Position = Total_Households / 2 ) %>% # 定位中位数所在的区间 filter(Cumulative_Count >= Median_Position) %>% slice(1) %>% # 取第一个满足条件的区间 mutate( # 用线性插值公式计算精确中位数:L + (N/2 - F)/f * w # L=区间下限,N=总家庭数,F=前一区间累计数,f=当前区间家庭数,w=区间宽度 Interval_Lower = as.numeric(strsplit(gsub(",", "", Income_Interval), "-")[[1]][1]), Interval_Upper = as.numeric(strsplit(gsub(",", "", Income_Interval), "-")[[1]][2]), Interval_Width = Interval_Upper - Interval_Lower, Previous_Cumulative = ifelse(row_number() == 1, 0, lag(Cumulative_Count)), Median_Income = Interval_Lower + (Median_Position - Previous_Cumulative)/Household_Count * Interval_Width ) %>% select(Neighborhood, Total_Households, Median_Income) %>% ungroup() # 查看最终结果 print(neighborhood_median)
几个注意点
- 如果你的原始数据里
1500-19999不是笔误,记得调整区间处理的逻辑; - 你提供的数据有未完成的行(比如
35000-39999对应的部分数值),计算前一定要补全完整数据,否则结果会偏差; - 这种线性插值的方法是分组数据计算中位数的标准做法,比直接用中点加权更贴近真实中位数。
内容的提问来源于stack exchange,提问作者mshwall
相关产品推荐
相关产品推荐

