如何用Python计算各地理区域通勤距离的均值与中位数?
普查通勤数据的均值与中位数计算问题
我是Python数据分析新手,正在处理普查通勤数据。示例数据如下:
| geo_area | Total | 2-5km | 5-10km |
|---|---|---|---|
| E02000001 | 5378 | 385 | 241 |
| E02000002 | 3238 | 474 | 394 |
| E02000003 | 5238 | 603 | 541 |
| E02000004 | 3113 | 354 | 277 |
| E02000005 | 4862 | 684 | 532 |
| E02000006 | 4271 | 676 | 408 |
其中第一列为地理区域,第二列为总通勤人数,其余列为对应距离区间(2-5km、5-10km等)的通勤人数频次(实际数据超7000行,省略了其他距离区间列)。我需要计算每个地理区域的通勤距离均值和中位数。
我自行编写了以下中位数计算函数,但不确定是否正确:
def median_calculator(df): full_list_of_numbers = [] for col in df.columns: full_list_of_numbers.append(((df[col].cumsum() - (df[col].sum(axis=0)/2).T) < 0).sum()) return full_list_of_numbers
目前我卡在均值计算上,同时想咨询是否可以通过df.groupby('geographical_areas').agg({mean_distance: 'mean', 'median_distance':'median'})来实现需求?
均值计算方法
计算通勤距离均值的核心是给每个距离区间设定区间中点,再通过加权平均计算:
- 先为所有距离区间定义中点值(比如
2-5km取3.5km,5-10km取7.5km) - 对每个地理区域,用「区间中点 × 该区间通勤人数」的总和,除以总通勤人数,得到均值
示例代码:
import pandas as pd # 读取数据(示例) df = pd.DataFrame([ ["E02000001", 5378, 385, 241], ["E02000002", 3238, 474, 394], ["E02000003", 5238, 603, 541], ["E02000004", 3113, 354, 277], ["E02000005", 4862, 684, 532], ["E02000006", 4271, 676, 408] ], columns=["geo_area", "Total", "2-5km", "5-10km"]) # 定义所有区间的中点映射 distance_midpoints = { "2-5km": 3.5, "5-10km": 7.5 # 补充其他距离区间的中点值 } # 计算每个区域的加权均值 df["mean_distance"] = df.apply( lambda row: sum(row[col] * distance_midpoints[col] for col in distance_midpoints) / row["Total"], axis=1 )
中位数函数的问题
你当前的中位数函数逻辑存在错误:
- 函数遍历的是列,但实际需要按**行(单个地理区域)**计算中位数
- 逻辑未结合区间的距离信息,仅对列累计值做判断,无法得到实际通勤距离的中位数
正确的中位数计算逻辑:
- 按距离从小到大遍历区间,构建每个区域的累计人数分布
- 找到累计人数超过总人数一半的第一个区间,通过线性插值计算精确中位数
示例代码:
def calculate_median(row, interval_order, interval_midpoints): total = row["Total"] cumulative = 0 prev_interval = None # 按距离从小到大遍历区间 for interval in interval_order: count = row[interval] cumulative += count # 找到中位数所在区间 if cumulative >= total / 2: prev_cumulative = cumulative - count # 线性插值计算精确中位数 lower_bound = interval_midpoints[prev_interval] if prev_interval else 0 median = lower_bound + (total/2 - prev_cumulative)/count * (interval_midpoints[interval] - lower_bound) return median prev_interval = interval return 0 # 定义区间的从小到大顺序 interval_order = ["2-5km", "5-10km"] # 补充其他区间 # 区间中点映射(与均值计算一致) interval_midpoints = {"2-5km":3.5, "5-10km":7.5} # 计算每个区域的中位数 df["median_distance"] = df.apply(lambda row: calculate_median(row, interval_order, interval_midpoints), axis=1)
关于groupby的疑问
你提到的groupby写法无法直接实现需求:
- 你的数据每行对应一个地理区域,不需要分组聚合(
groupby用于对多行同组数据聚合,这里每个组就是单行) mean_distance和median_distance是需要计算的衍生列,不是原始数据列,无法直接在agg中调用
正确做法是先按上述方法计算出mean_distance和median_distance列,若后续需要按其他维度分组,再使用groupby。
内容的提问来源于stack exchange,提问作者UbuntuPython
相关产品推荐
相关产品推荐

