最近站点去重,密集站点抽稀
工作中常常遇到多个站点密集在一起,如ABCD,A最近的是B,B最近的是C,需要将这些站点进行抽稀处理。经过几翻折腾,终于搞定,处理工具如下:
假设已有以下数据:
import pandas as pd
from math import (pi, radians, sin, cos, asin, sqrt, degrees, atan2, ceil)
#定义距离计算方法
def calculate_distance(lon1, lat1, lon2, lat2):
lon1, lat1, lon2, lat2 = map(radians, [float(lon1), float(lat1), float(lon2), float(lat2)])
d_lon, d_lat = lon2 - lon1, lat2 - lat1
am = sin(d_lat / 2) ** 2 + cos(lat1) * cos(lat2) * sin(d_lon / 2) ** 2
distance = 2 * asin(sqrt(am)) * 6371229
return float('%.4f' % distance)
def run_site_filter():
df = pd.read_excel(path_in, sheet_name='密集站点抽稀处理')
# 定义列表集,用于存放删除了哪些站点
temp_del_all = []
# 程序需要无限循环操作,直到将需要的距离范围内最近的站点全部清除为止。
m = 1
while True:
# 定义处理过程的表df_x
df_x = []
for numb_a, lon_a, lat_a, info_a in zip(df.编号, df.经度, df.纬度, df.信息1):
for numb_b, lon_b, lat_b, info_b in zip(df.编号, df.经度, df.纬度, df.信息1):
if numb_a != numb_b:
temp_distance = calculate_distance(lon_a, lat_a, lon_b, lat_b)
df_x.append([numb_a, info_a, numb_b, info_b, temp_distance])
# 每一次的计算结果表,此表后面还要用到
df_x = pd.DataFrame(df_x)
df_x['rank'] = df_x.groupby([0]).rank(method='dense', ascending=1)[4] # 按基站名和距离来排序
df_x_rank_3 = df_x[df_x['rank'] <= 3]
df_x_rank_3_mean = df_x_rank_3.groupby(0)[4].mean() # 每一个站点最近3处点的平均距离,用于空间考虑,尽量保留空间位置较稀疏的点位。
distance_values_min = df_x[4].min() # df_x[4]代表temp_distance列,筛选出距离最小的值
df_x_min = df_x[df_x[4] == distance_values_min]
# 如果距离小于300米,就继续进行数据处理,一直到没有小于300米的为止。
if distance_values_min <= float(filter_distance_value):
# 处理过程中要保留谁?要删掉谁?需要在模板中给每个站点的一个权值,根据权值来判断;
temp_del = []
for x, x_info, y, y_info in zip(df_x_min[0], df_x_min[1], df_x_min[2], df_x_min[3]):
if x_info > y_info:
temp_del.append(y)
elif x_info < y_info:
temp_del.append(x)
elif x_info == y_info:
if df_x_rank_3_mean[x] < df_x_rank_3_mean[y]:
temp_del.append(x)
elif df_x_rank_3_mean[x] > df_x_rank_3_mean[y]:
temp_del.append(y)
elif df_x_rank_3_mean[x] == df_x_rank_3_mean[y]:
if (x not in temp_del) & (y not in temp_del):
temp_del.append(y)
elif (x in temp_del) & (y not in temp_del):
temp_del.append(x)
elif (x not in temp_del) & (y in temp_del):
temp_del.append(y)
elif (x in temp_del) & (y in temp_del):
temp_del.append('no,all in temp_del')
else:
temp_del.append('其他情况,需人工分析')
temp_del_remove_duplicates = list(set(temp_del))
temp_del_all.append(temp_del_remove_duplicates) # 将要删除的站点放入列表中
# 删除df0表中不需要的站点
for i in temp_del_remove_duplicates:
df = df[df['编号'] != i]
df = pd.DataFrame(df) # 得到删除后的、剩余的站点列表,df表第一次处理完成。
temp_view = ' Please wait' + '\t' + str(m) + '\t' + str(distance_values_min)
print(temp_view)
else:
print("用户指定距离范围内的运算已完成!")
break
m += 1
# 输出要删除的站点清单
temp_del_all = pd.DataFrame(temp_del_all)
file_del_path = r'D:\xxx删除的站点.xlsx'
temp_del_all.to_excel(file_del_path, index=None, encoding='gbk')
# 输出最终要保留下来的站点清单
file_save_path = r'D:\xxx保留的站点.xlsx'
df.to_excel(file_save_path, index=None, encoding='gbk')
print("运算全部完成,请查看输出的EXCEL文件")
if __name__ == '__main__':
path_in = r'D:\经纬度信息表.xlsx'
filter_distance_value = 300 # 指定需要处理的距离,米
run_site_filter()