Como encontrar a localização dos pontos mais densos do mapa?

  Recentemente, encontrei uma pequena necessidade no trabalho: provavelmente era necessário exibir o local com a densidade de pontos mais densa entre vários pontos no mapa. Não pensei em um bom método no início, então usei uma estratégia muito simples - calculando a média das coordenadas de todos os pontos. Este método é fácil de usar na maioria das vezes, porque todos os pontos na maioria das cidades estão basicamente em torno de um determinado centro Os pontos se espalham em todas as direções. Mas quando o usamos on-line, encontramos dois casos especiais.

  A primeira é que quando a distribuição de pontos mostra uma forma anormal, como dados em forma de haltere distribuídos em ambas as extremidades, seu método médio encontrará o local com a densidade de dados mais esparsa no meio, assim como encontramos nos dados de Chengdu, conforme mostrado abaixo O ponto vermelho é o ponto central calculado com base no valor médio.
Insira a descrição da imagem aqui
  Outro caso anormal é quando os dados mostram uma distribuição circular, como os dados de Pequim. O centro de Pequim é a Cidade Proibida. É impossível termos um ponto. Se calcularmos diretamente a média, o ponto central calculado é perto da Cidade Proibida. Aqui Os dados são os mais esparsos, conforme mostrado na figura abaixo.
Insira a descrição da imagem aqui
  Mais tarde, pesquisei as informações e descobri que o método de densidade do kernel pode resolver os problemas que encontramos.Após experimentos, descobrimos que o efeito não é ruim, então vou compartilhá-lo com vocês aqui. A ideia de densidade do kernel também é muito simples, que consiste em percorrer todos os pontos, calcular o valor total da densidade do kernel de outros pontos até o ponto atual e, em seguida, encontrar o ponto com a maior densidade média. Como um exemplo simples, dado um ponto, se algum outro ponto estiver próximo deste ponto, o valor da densidade será alto, caso contrário estará longe. A média da soma da densidade deste ponto para todos os outros pontos é a densidade final valor deste ponto, aqui podemos usar diretamente o recíproco da distância como a função kernel, mas esta função kernel é linear e o resultado final não é muito diferente do meu valor médio.

  Otimizando a ideia, se a distância entre um determinado ponto for mais distante, o valor da densidade trazido por ele deveria ser menor? Os antecessores também pensavam assim, então havia muitas funções de kernel não lineares, e finalmente usei o kernel gaussiano. Depois de ajustar a largura de banda da função de kernel, os valores de densidade trazidos por outros pontos também serão distribuídos normalmente com a distância. O método de atenuação é como mostrado na figura abaixo. Por exemplo, quanto mais distante estiver o valor da coordenada do eixo vertical, menor será o valor da coordenada. O sigma na figura é a largura de banda da nossa função kernel.
Insira a descrição da imagem aqui
  A seguir, vamos dar uma olhada no processo de cálculo e nos efeitos. Como somos um sistema Java, minha implementação final é usar java para chamar o pacote simples. O código geral é o seguinte:

	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];
	}

  Aqui usei 0,02 para a largura de banda (sigma no kernel gaussiano). Isso também é o resultado de múltiplas depurações. Se for muito grande, o valor de densidade calculado estará mais próximo da média global. Se for muito pequeno, vários pontos aparecerão juntos., mas não há outros pontos ao redor. Vamos pegar os dois casos anormais acima para ver o efeito do método de densidade do kernel. O primeiro são os dados do tipo haltere Chengdu.
Insira a descrição da imagem aqui
A seguir estão os dados anulares de Pequim
Insira a descrição da imagem aqui
  . Na imagem acima, usei sklearn em python para implementar a densidade do kernel e folium para desenhar o mapa. O código completo também foi postado para sua referência.

# -*- 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')

Acho que você gosta

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