¿Cómo encontrar la ubicación de los puntos más densos en el mapa?

  Recientemente, encontré una pequeña necesidad en el trabajo: probablemente era necesario mostrar la ubicación con la mayor densidad de puntos entre un montón de puntos en el mapa. Al principio no pensé en un buen método, así que utilicé una estrategia muy simple: promediar las coordenadas de todos los puntos. Este método es fácil de usar la mayor parte del tiempo, porque todos los puntos en la mayoría de las ciudades están básicamente alrededor de un determinado centro. Los puntos se extienden en todas direcciones. Pero cuando lo usamos en línea, encontramos dos casos especiales.

  La primera es que cuando la distribución de puntos muestra una forma anormal, como datos en forma de mancuerna distribuidos en ambos extremos, su método promedio encontrará el lugar con la densidad de datos más escasa en el medio, tal como lo encontramos en los datos de Chengdu. como se muestra a continuación. El punto rojo es el punto central calculado en función del valor promedio.
Insertar descripción de la imagen aquí
  Otro caso anormal es cuando los datos muestran una distribución circular, como los datos de Beijing, el centro de Beijing es la Ciudad Prohibida, no podemos ser un poquito, si el promedio se calcula directamente, el punto central calculado está cerca la Ciudad Prohibida, aquí Los datos son los más escasos, como se muestra en la siguiente figura.
Insertar descripción de la imagen aquí
  Más tarde verifiqué la información y descubrí que el método de densidad del núcleo puede resolver los problemas que encontramos. Después del experimento, descubrí que el efecto no es malo, así que lo compartiré con ustedes aquí. La idea de la densidad del kernel también es muy simple, es decir, atravesar todos los puntos, calcular el valor total de la densidad del kernel desde otros puntos hasta el punto actual y luego encontrar el punto con la densidad promedio más alta. Para dar un ejemplo simple, dado un punto, si algún otro punto está cerca de este punto, el valor de densidad será alto, de lo contrario estará muy lejos, y el promedio de la densidad desde este punto hasta todos los demás puntos es el resultado final. valor de densidad de este punto, aquí Podemos usar directamente el recíproco de la distancia como función central, pero esta función central es lineal y el resultado final no es muy diferente de mi valor promedio.

  Optimizando la idea, si la distancia entre un determinado punto es mayor, ¿debería ser menor el valor de densidad que aporta? Los predecesores también pensaban lo mismo, por lo que había muchas funciones del núcleo no lineales, y finalmente utilicé el núcleo gaussiano. Después de ajustar el ancho de banda de la función del núcleo, los valores de densidad aportados por otros puntos también se distribuirán normalmente con la distancia. La atenuación es como se muestra en la siguiente figura. Por ejemplo, cuanto más lejos esté el valor de las coordenadas del eje vertical, menor será el valor de las coordenadas. La sigma en la figura es el ancho de banda de nuestra función central.
Insertar descripción de la imagen aquí
  A continuación, echemos un vistazo al proceso de cálculo y sus efectos. Dado que somos un sistema Java, mi implementación final es usar Java para llamar al paquete simple. El código general es el siguiente:

	private double[] getHotpot(double[][] data) {
    
    
		// 创建高斯核
		MercerKernel<double[]> kernel = new GaussianKernel(0.02);

		// 计算所有点的核密度估计
		double[] densities = new double[data.length];
		for (int i = 0; i < data.length; i++) {
    
    
			for (int j = 0; j < data.length; j++) {
    
    
				densities[i] += kernel.k(data[i], data[j]);
			}
			// 计算平均密度
			densities[i] /= data.length;
		}

		// 找出密度最大的点
		int maxDensityIndex = 0;
		for (int i = 1; i < densities.length; i++) {
    
    
			if (densities[i] > densities[maxDensityIndex]) {
    
    
				maxDensityIndex = i;
			}
		}
		return data[maxDensityIndex];
	}

  Aquí utilicé 0,02 para el ancho de banda (sigma en el núcleo gaussiano). Esto también es el resultado de múltiples depuraciones. Si es demasiado grande, el valor de densidad calculado estará más cerca del promedio global. Si es demasiado pequeño, varios puntos aparecerán juntos, pero no hay otros puntos alrededor. Tomemos los dos casos anormales anteriores para ver el efecto del método de densidad del núcleo. El primero son los datos del tipo con mancuernas de Chengdu.
Insertar descripción de la imagen aquí
Lo siguiente son los datos anulares de Beijing
Insertar descripción de la imagen aquí
  . En la imagen de arriba, utilicé sklearn en Python para implementar la densidad del núcleo y folium para dibujar el mapa. El código completo también se publica para su referencia.

# -*- coding: utf-8 -*-
import folium
import pandas as pd
from sklearn.neighbors import KernelDensity
import numpy as np

def getCenterPoint(sites):
    points = sites[['latitude', 'longitude']].values
    weights = sites['score'].values
    
    # 实例化KernelDensity对象
    kde = KernelDensity(kernel='gaussian', bandwidth=0.02)

    # 对数据进行拟合
    kde.fit(points) 

    # 使用KDE模型评估每个点的密度
    log_densities = kde.score_samples(points)

    # 密度最高的点是评估密度最高(即,log_densities值最大)的点
    highest_density_point = points[np.argmax(log_densities)]

    print(highest_density_point.tolist())
    return highest_density_point.tolist()

# 创建一个以给定经纬度为中心的地图,初始缩放级别设为14
m = folium.Map(zoom_start=14)

for i, s in data.iterrows():
    # 在地图上添加一个点标记
    folium.Marker(
        location=[s['latitude'], s['longitude']],  # 经纬度
        popup=s['resblock'], 
    ).add_to(m)
# 保存为html文件
centerPoint = getCenterPoint(cityDf)
folium.Marker(
    location=centerPoint,  # 经纬度
    popup='中心点',  # 弹出内容
    radius=50,
    icon=folium.Icon(color="red", icon="info-sign")
).add_to(m)

m.location = centerPoint

m.save('map.html')

Supongo que te gusta

Origin blog.csdn.net/xindoo/article/details/132515004
Recomendado
Clasificación