双循环遍历DataFrame时索引j未更新问题及坐标合并需求求助
合并近似坐标地点并统计数量的问题排查
我有一个包含未知地点经纬度的DataFrame,其中存在大量坐标近似的地点。希望生成一个“过滤后未知地点”的DataFrame,将近似坐标的地点合并为一个,并统计每个合并后地点包含的原地点数量。
尝试用两层for循环解决,代码如下:
accuracy = 0.2 #km df_unknown_places_filtered = pd.DataFrame(columns = ['GpsLatitude', 'GpsLongitude', 'Count']) for i, row in df_unknown_places.iterrows(): min_dist = 999999 closest = 0 for j, row2 in df_unknown_places_filtered.iterrows(): dist = self.distance(row['GpsLatitude'], row['GpsLongitude'], row2['GpsLatitude'], row2['GpsLongitude']) if dist < min_dist: min_dist = dist closest = j if min_dist < accuracy: current_count = df_unknown_places_filtered.at[closest, 'Count'] df_unknown_places_filtered.at[closest,'Count'] = current_count + 1 else: row_to_insert = {'GpsLatitude':row['GpsLatitude'], 'GpsLongitude':row['GpsLongitude'], 'Count': 1 } df_unknown_places_filtered = pd.concat([df_unknown_places_filtered, pd.DataFrame.from_records([row_to_insert])], axis = 0)
但内层iterrows()的j值并未正确更新,导致逻辑出错,问题出在这几个地方:
- 索引混乱:每次用
pd.concat新增行时,新生成的单行DataFrame默认索引是0,导致过滤表的索引重复,iterrows()返回的j会重复出现,你误以为是j没更新,实际是索引重复导致定位错误。 - 初始值不合理:
closest初始化为0,当过滤表为空时内层循环不执行,这时候虽不会触发更新逻辑,但当过滤表有重复索引时,at[closest, 'Count']会修改错误的行。 - 效率极低:两层循环+频繁
concat拼接DataFrame,不仅速度慢,还容易引发索引问题。
修复方案
方案1:修复原有逻辑,改用列表维护中间数据
用列表代替DataFrame存储过滤后的结果,避免索引混乱,同时提升效率:
accuracy = 0.2 # km filtered_data = [] # 用列表存储中间结果,避免索引问题 for _, row in df_unknown_places.iterrows(): min_dist = 999999 closest_idx = -1 # 初始化为-1,表示未找到匹配项 # 遍历列表,用enumerate拿到正确的索引 for idx, item in enumerate(filtered_data): dist = self.distance(row['GpsLatitude'], row['GpsLongitude'], item['GpsLatitude'], item['GpsLongitude']) if dist < min_dist: min_dist = dist closest_idx = idx # 找到近似地点则计数+1 if min_dist < accuracy and closest_idx != -1: filtered_data[closest_idx]['Count'] += 1 # 否则新增地点 else: filtered_data.append({ 'GpsLatitude': row['GpsLatitude'], 'GpsLongitude': row['GpsLongitude'], 'Count': 1 }) # 最后将列表转为DataFrame df_unknown_places_filtered = pd.DataFrame(filtered_data)
方案2:用DBSCAN空间聚类(大数据量首选)
如果数据量较大,两层循环的O(n²)效率极低,推荐用专门的空间聚类算法DBSCAN,结果更准确且效率更高:
from sklearn.cluster import DBSCAN import numpy as np # 将经纬度转为弧度(haversine度量要求输入弧度) coords = np.radians(df_unknown_places[['GpsLatitude', 'GpsLongitude']].values) # eps=0.2/6371:将0.2公里转为弧度(6371是地球平均半径,单位公里) # min_samples=1:允许单个点作为一个聚类 db = DBSCAN(eps=0.2/6371, min_samples=1, metric='haversine').fit(coords) # 给原数据添加聚类标签 df_unknown_places['cluster'] = db.labels_ # 按聚类标签分组,统计数量并取每组平均坐标(也可以取第一个点的坐标) df_unknown_places_filtered = df_unknown_places.groupby('cluster').agg( GpsLatitude=('GpsLatitude', 'mean'), GpsLongitude=('GpsLongitude', 'mean'), Count=('cluster', 'count') ).reset_index(drop=True)
内容的提问来源于stack exchange,提问作者Sjig
相关产品推荐
相关产品推荐

