This attempt is not finished yet, because it requires Ellipsoidal distance instead of Cartesian.
As you can see in the source code
spatialIndex = QgsSpatialIndex(source, feedback)
distance = QgsDistanceArea()
distance.setSourceCrs(source.sourceCrs(), context.transformContext())
distance.setEllipsoid(context.project().ellipsoid())
There is also no spatial index implemented in my solution.
I hope with my answer I do not collide with the author copyrights of this particular tool.
First of all, I will credit here: Victor Olaya and his code QGIS/python/plugins/processing/algs/qgis/NearestNeighbourAnalysis.py that can be partially reproduced.
And secondly partial credits to @rdmolony with this answer.
Let's assume there is a shapefile called 'points' with 10 point features in it, see the image below.
After applying the "Nearest neighbour analysis" I could get the following output:
Using the following code in Python:
import math
import shapely.geometry
import geopandas as gpd
from shapely.ops import nearest_points
absolute_path_to_shapefile = 'P:/Test/qgis_test/points.shp'
gdf = gpd.read_file(absolute_path_to_shapefile)
count = len(gdf)
total = 100.0 / count if count else 1
bbox = gdf.total_bounds
polygon = shapely.geometry.box(*bbox, ccw=True)
area = polygon.area
def get_nearest_values(row, other_gdf, point_column='geometry', value_column="geometry"):
"""
Find the nearest point and return the corresponding value from specified value column.
"""
# Create an union of the other GeoDataFrame's geometries:
other_points = other_gdf["geometry"].unary_union
other_points = other_points.difference(row[point_column])
# Find the nearest points
nearest_geoms = nearest_points(row[point_column], other_points)
# Get corresponding values from the other df
nearest_data = other_gdf.loc[other_gdf["geometry"] == nearest_geoms[1]]
nearest_value = nearest_data[value_column].values[0]
return nearest_value
gdf['Nearest'] = gdf.apply(lambda row: get_nearest_values(row, gdf), axis=1)
gdf['Distance'] = gdf.apply(lambda row: row.geometry.distance(row['Nearest']), axis=1)
sumDist = gdf['Distance'].sum()
do = float(sumDist) / count
de = float(0.5 / math.sqrt(count / area))
d = float(do / de)
SE = float(0.26136 / math.sqrt(count ** 2 / area))
zscore = float((do - de) / SE)
print(f'Observed mean distance: {do}')
print(f'Expected mean distance: {de}')
print(f'Nearest neighbour index: {d}')
print(f'Number of points: {count}')
print(f'Z-Score: {zscore}')
I could get the result like this :
Observed mean distance: 496517.1068282208
Expected mean distance: 302718.07444028446
Nearest neighbour index: 1.6401964360610586
Number of points: 10
Z-Score: 3.8729700181269147
References: