Message posté par : Abdoulayi111
----------------------------------------
Voici le code en question avec DBSCAN ci-dessous. Il ne répond pas à mes besoins à cause
de la non prise en compte du poids et de la distance maximum entre deux entités d'un
même cluster.
'''python
from sklearn.cluster import DBSCAN
import networkx as nx
import pandas as pd
import numpy as np
from qgis.core import QgsProject, QgsField, QgsFeatureIterator
from qgis.PyQt.QtCore import QVariant
class Clustering:
"""
Clustering logical grouping of points (populations) based on the linear networks (road
networks) """
def __init__(self, copy_network_layer, node_nearest_point_layer) -> None:
"""
:param copy_network_layer: copy_network_layer: name of the new network layer
:param node_nearest_point_layer: Name of the new node table.
"""
self.copy_network_layer = copy_network_layer
self.node_nearest_point_layer = node_nearest_point_layer
@staticmethod
def formation_graph_in_network(feat_network_layer: QgsFeatureIterator) -> nx:
"""
:param feat_network_layer: Network layer name
:return: Graph constitutes the origin and the end of the network
"""
network_graph = nx.Graph()
for feat_line in feat_network_layer:
start_point = feat_line.geometry().asPolyline()[0]
end_point = feat_line.geometry().asPolyline()[-1]
network_graph.add_edge(start_point, end_point)
return network_graph
@staticmethod
def association_node_closest_network(feat_points_layer: QgsFeatureIterator,
network_graph: nx) -> tuple[np, pd]:
"""
Association of each point entity to the network closest to it
:param feat_points_layer: point layer name
:param network_graph: origin and the end of the network
:return:
"""
# Récupération des points en utilisant qgis.core
points = []
gid = []
for feat_pt in feat_points_layer:
point = feat_pt.geometry().asPoint()
nearest_node = min(network_graph.nodes(),
key=lambda x: np.linalg.norm(np.array(x) -
np.array([point.x(),
point.y()])))
gid.append(feat_pt.id())
points.append(nearest_node)
data = pd.DataFrame({"gid": gid})
return np.array(points), data
def cluster_dbscan(self, field_weight: str) -> pd.DataFrame:
"""
:param field_weight: This field will be created for contains information cluster
The same cluster will have same number.
:return: Each entity is associated with the number of its cluster
"""
network_layer = QgsProject.instance().mapLayersByName(self.copy_network_layer)[0]
points_layer =
QgsProject.instance().mapLayersByName(self.node_nearest_point_layer)[0]
network_graph = self.formation_graph_in_network(network_layer.getFeatures())
points, clustering =
self.association_node_closest_network(points_layer.getFeatures(),
network_graph)
# Clustering en utilisant DBSCAN
# esp : distance maximale entre deux échantillons pour qu'ils soient
considérés comme
# faisant partie du même voisinage. Il ne s'agit pas de distance entre toutes
les éléments d'un même cluster
# min_samples : nombre minimum d'échantillons requis pour former une densité
d'échantillons
dbscan = DBSCAN(eps=500, min_samples=3, algorithm="auto")
clustering[field_weight] = dbscan.fit_predict(points)
points_layer.dataProvider().addAttributes([QgsField("label",
QVariant.Int,
comment="Valeur des
cluster")])
points_layer.updateExtents()
points_layer.updateFields()
# If not existe, it will be create
idx_label = points_layer.fields().indexFromName("label")
for [gid, label] in clustering.values:
attrs = {idx_label: int(label)}
points_layer.dataProvider().changeAttributeValues({gid: attrs})
return clustering
if __name__ == "__main__":
cluster_instance = Clustering("network_layer", "pt_node_nearest")
cluster_instance.cluster_dbscan("poids")
'''
----------------------------------------
Le message est situé
https://georezo.net/forum/viewtopic.php?pid=358521#p358521
Pour y répondre : geomatique(a)ml.georezo.net ou reply de votre messagerie
Pour vous désabonner connectez-vous sur le forum puis Profil / Abonnement
--
Association GeoRezo - le portail géomatique
https://georezo.net