如何通过匹配Total_Area与Basement_Area最近值填充DataFrame字段
问题描述
我有两个DataFrame:
df1:
Year City Address Total_Area Basement_Area 1989 Ottawa empty 280 130
另一个更大的df2需要通过Total_Area和Basement_Area匹配最近邻:
df2:
Year Address(with city in it) Total_Area Basement_Area 1989 123 Test Ottawa 279 120 1989 146 Test Ottawa 276 140 1989 156 Test Ottawa 283 134
期望结果是将df1的Address字段替换为匹配到的地址:
Year City Address Total_Area Basement_Area 1989 Ottawa 156 Test Ottawa 280 130
我尝试写了如下函数,但无法正确筛选并获取目标地址,求指导:
def filter_df(df,year,city,basement=0, floor_area=0, heated_floor_area=0,mp_storeys=0): if basement == 0: df = df[df[const.BASEMENT_COLUMN_df2_NAME].isnull()] else: df = df[(df[const.BASEMENT_COLUMN_df2_NAME]- floor_area).abs()< 10] filtered_df = df[(df[const.YEAR_COLUMN_df2_NAME] == year)] filtered_df = df[(df[const.ADDRESS_COLUMN_df2_NAME].str.contains(city))] filtered_df = df[(df[const.TOTAL_AREA_COLUMN_df2_NAME] - floor_area).abs()< 10] return filtered_df[0]
问题分析与修正
你的函数存在几个关键问题:
- 筛选逻辑覆盖错误:每次赋值
filtered_df = df[xxx]都会覆盖之前的筛选结果,而非叠加条件。比如先按年份筛选后,直接用原始df按地址包含城市筛选,之前的年份筛选就失效了。 - 地下室面积匹配逻辑错误:else分支里用
Basement_Area - floor_area计算差值,应该和传入的basement参数比较,而非floor_area。 - 最近邻匹配缺失:当前代码只做了阈值内的筛选,没有在符合条件的结果里找到与df1数据最接近的行。
- 结果取值错误:
filtered_df[0]不是正确的取行方式,需用.iloc[0],且要先确保筛选后有结果。
下面是修正后的代码,实现基于Total_Area和Basement_Area的欧氏距离最近邻匹配:
import numpy as np def filter_df(df, year, city, basement=0, floor_area=0, **kwargs): # 1. 基础筛选:年份匹配 + 地址包含城市 filtered_df = df[ (df[const.YEAR_COLUMN_df2_NAME] == year) & (df[const.ADDRESS_COLUMN_df2_NAME].str.contains(city, na=False)) ] # 2. 地下室面积筛选:传入非0值时,保留差值在10以内的行 if basement != 0: filtered_df = filtered_df[ (filtered_df[const.BASEMENT_COLUMN_df2_NAME] - basement).abs() < 10 ] # 3. 总面积筛选:保留差值在10以内的行 filtered_df = filtered_df[ (filtered_df[const.TOTAL_AREA_COLUMN_df2_NAME] - floor_area).abs() < 10 ] # 4. 计算欧氏距离,找到最近邻 if not filtered_df.empty: # 计算每行与目标值的距离 filtered_df['distance'] = np.sqrt( (filtered_df[const.TOTAL_AREA_COLUMN_df2_NAME] - floor_area)**2 + (filtered_df[const.BASEMENT_COLUMN_df2_NAME] - basement)**2 ) # 取距离最小的行 nearest_row = filtered_df.sort_values('distance').iloc[0] return nearest_row[const.ADDRESS_COLUMN_df2_NAME] else: # 无匹配结果时返回None或原地址 return None # 调用示例:遍历df1批量替换地址 df1['Address'] = df1.apply( lambda row: filter_df( df2, year=row['Year'], city=row['City'], basement=row['Basement_Area'], floor_area=row['Total_Area'] ), axis=1 )
修正说明
- 用
&组合多个筛选条件,确保所有条件同时生效。 - 地下室面积的差值计算改为与传入的
basement参数对比,符合业务逻辑。 - 加入欧氏距离计算,在符合阈值的结果中找到最接近的行,实现最近邻匹配。
- 增加空值判断,避免筛选结果为空时报错。
- 使用
apply遍历df1每一行,批量完成地址替换。
内容的提问来源于stack exchange,提问作者Artur Akhmetgareev
相关产品推荐
相关产品推荐

