blob: 6f248775db3a45381e231af38c5086e4fa741b50 [file] [view]
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
## 概述
Sedona 的 stats 模块为带有空间列的 dataframe 提供了用于地理空间
统计分析的 Scala 和 Python 函数。
stats 模块构建在 core 模块之上,提供了一组可用于
对这些 dataframe 进行空间分析的函数。stats 模块设计上配合 core 模块以及
viz 模块共同使用,从而提供一套完整的地理空间分析工具。
## 使用 DBSCAN
DBSCAN 函数在 scala/java 中位于 `org.apache.sedona.stats.clustering.DBSCAN.dbscan`,在 python 中位于 `sedona.stats.clustering.dbscan.dbscan`。
该函数使用 DBSCAN 算法为 dataframe 的每一条记录标注一个聚类标签。
dataframe 应至少包含一列 `GeometryType` 类型的列。各行必须唯一。如果仅有一列
几何列,会自动使用该列。如果有两列,会使用名为
'geometry' 的那一列。如果有多于一列且没有任何一列名为 'geometry',则
必须显式提供列名。新增列将命名为 'cluster'。
### 参数
括号中的名字是 python 中的变量名
- dataframe —— 待聚类的 dataframe。必须包含至少一列 GeometryType 列
- epsilon —— DBSCAN 算法的最小距离参数
- minPts (min_pts) —— DBSCAN 算法的最小点数参数
- geometry —— 几何列的列名
- includeOutliers (include_outliers) —— 是否在输出中包含离群点。默认为 false
- useSpheroid (use_spheroid) —— 是否使用椭球距离计算(而非笛卡尔距离)。默认为 false
输出是输入 DataFrame,每一行新增了聚类标签。如果包含离群点,离群点的聚类值为 -1。
## 使用局部离群因子(LOF)
LOF 函数在 scala/java 中位于 `org.apache.sedona.stats.outlierDetection.LocalOutlierFactor.localOutlierFactor`,在 python 中位于 `sedona.stats.outlier_detection.local_outlier_factor.local_outlier_factor`。
该函数为 dataframe 的每一条记录新增一列,记录其局部离群因子。
dataframe 应至少包含一列 `GeometryType` 类型的列。各行必须唯一。如果仅有一列
几何列,会自动使用该列。如果有两列,会使用名为
'geometry' 的那一列。如果有多于一列且没有任何一列名为 'geometry',则
必须显式提供列名。
### 参数
括号中的名字是 python 中的变量名
- dataframe —— 包含点几何对象的 dataframe
- k —— 计算 LOF 时考虑的最近邻居的数量
- geometry —— 几何列的列名
- handleTies (handle_ties) —— 是否在 k 距离计算中处理并列情形。默认为 false
- useSpheroid (use_spheroid) —— 是否使用椭球距离计算(而非笛卡尔距离)。默认为 false
输出是输入 DataFrame,每一行新增了 lof 值。
## 使用 Getis-Ord Gi(*)
G Local 函数在 scala/java 中位于 `org.apache.sedona.stats.hotspotDetection.GetisOrd.gLocal`,在 python 中位于 `sedona.stats.hotspot_detection.getis_ord.g_local`。
对 dataframe 的 x 列执行 Gi 或 Gi* 统计。
权重应为本行的邻居。权重元素应为包含 value 列与 neighbor 列的结构体。neighbor 列的内容应是
与父行同类型的邻居(但不再包含 neighbors)。生成此列的方法请参见 _Using the Distance
Weighting Function_ 一节。要计算 Gi*
统计量,请确保焦点观测值位于邻居数组中(即本行本身出现在 weights 列中)且 `star=true`。显著性通过 z 分数计算。
### 参数
- dataframe —— 用于执行 G 统计的 dataframe
- x —— 要执行热点分析的列名
- weights —— 包含邻居数组的列名。neighbor 列的内容应是与父行同类型的邻居(但不再包含 neighbors)。你可以使用 `Weighting` 类的函数来生成该列。
- star —— 焦点观测值是否包含在邻居数组中。若为 true 则计算 Gi*,否则计算 Gi
输出是输入 DataFrame,每一行新增以下列:G、E[G]、V[G]、Z、P。
## 使用距离加权函数
Weighting 相关函数在 scala/java 中位于 `org.apache.sedona.stats.Weighting`,在 python 中位于 `sedona.stats.weighting`。
该函数会新增一列,包含一组由 value 列和 neighbor 列构成的结构体数组。
通用的 `addDistanceBandColumn`(python 中为 `add_distance_band_column`)函数会为 dataframe 添加一个 weights 列,包含距离阈值内的其他记录及其权重。
dataframe 应至少包含一列 `GeometryType` 类型的列。各行必须唯一。如果仅有一列
几何列,会自动使用该列。如果有两列,会使用名为
'geometry' 的那一列。如果有多于一列且没有任何一列名为 'geometry',则
必须显式提供列名。新增列将命名为 'cluster'。
### 参数
#### addDistanceBandColumn
括号中的名字是 python 中的变量名
- dataframe —— 包含几何列的 DataFrame
- threshold —— 判定邻居的距离阈值
- binary —— 邻居使用二进制权重还是反距离权重(dist^alpha)
- alpha —— 反距离权重使用的 alpha 值,当 binary 为 true 时忽略
- includeZeroDistanceNeighbors (include_zero_distance_neighbors) —— 是否包含距离为 0 的邻居。若包含且 binary 为 false,按浮点规范(除以 0),其值会是无穷大
- includeSelf (include_self) —— 是否将自身包含在邻居列表中
- selfWeight (self_weight) —— 自身权重的取值
- geometry —— 几何列的列名
- useSpheroid (use_spheroid) —— 是否使用椭球距离计算(而非笛卡尔距离)。默认为 false
#### addBinaryDistanceBandColumn
括号中的名字是 python 中的变量名
- dataframe —— 包含几何列的 DataFrame
- threshold —— 判定邻居的距离阈值
- includeZeroDistanceNeighbors (include_zero_distance_neighbors) —— 是否包含距离为 0 的邻居。若包含且 binary 为 false,按浮点规范(除以 0),其值会是无穷大
- includeSelf (include_self) —— 是否将自身包含在邻居列表中
- selfWeight (self_weight) —— 自身权重的取值
- geometry —— 几何列的列名
- useSpheroid (use_spheroid) —— 是否使用椭球距离计算(而非笛卡尔距离)。默认为 false
以上两种函数的输出均为输入 DataFrame,每一行新增 weights 列。
## Moran I
Moran I 是一种空间自相关算法,它同时使用空间
位置和非空间属性。当取值接近 1 时
表示存在空间相关性;当取值接近 0 时
表示不存在相关性,数据随机分布;当
MoranI 自相关值接近 -1 时表示存在负
相关。负相关意味着邻近的取值彼此差异较大。
下图展示了不同空间相关性的取值
- 左侧为负相关(-1)
- 中间为正相关(1)
- 右侧相关性接近 0,数据是随机的。
![moranI.png](../../image/moranI.png)
Moran 统计可以作为 Scala/Java 与 Python 函数使用。
该输入函数需要一个 weight DataFrame。你可以用
Apache Sedona 的加权函数来构造该 weight DataFrame。需要注意的是,
你的输入必须包含一个唯一标识要素的 id 列以及一个 value 字段。MoranI Apache Sedona 函数
所需的最简 schema 如下:
```
|-- id: integer (nullable = true)
|-- value: double (nullable = true)
|-- weights: array (nullable = false)
| |-- element: struct (containsNull = false)
| | |-- neighbor: struct (nullable = false)
| | | |-- id: integer (nullable = true)
| | | |-- value: double (nullable = true)
| | |-- value: double (nullable = true)
```
你可以通过函数参数控制 value 列的列名和 id。
要使用 [Apache Sedona 权重函数](#adddistancebandcolumn),需要把 id 列和 value 列传给保留参数。
=== "Scala"
```scala
val weights = Weighting.addDistanceBandColumn(
positiveCorrelationFrame,
1.0,
savedAttributes = Seq("id", "value")
)
val moranResult = Moran.getGlobal(weights, idColumn = "id")
// result fields
moranResult.getPNorm
moranResult.getI
moranResult.getZNorm
```
=== "Python"
```python
from sedona.spark.stats.autocorrelation.moran import Moran
from sedona.spark.stats.weighting import add_binary_distance_band_column
result = add_binary_distance_band_column(df, 1.0, saved_attributes=["id", "value"])
moran_i_result = Moran.get_global(result)
## result fields
moran_i_result.p_norm
moran_i_result.i
moran_i_result.z_norm
```
结果中会得到 Z norm、P norm 以及 Moran I 值。
下面是函数的完整签名
=== "Scala"
```scala
def getGlobal(
dataframe: DataFrame,
twoTailed: Boolean = true,
idColumn: String = ID_COLUMN,
valueColumnName: String = VALUE_COLUMN): MoranResult
// java interface
public interface MoranResult {
public double getI();
public double getPNorm();
public double getZNorm();
}
```
=== "Python"
```python
def get_global(
df: DataFrame,
two_tailed: bool = True,
id_column: str = "id",
value_column: str = "value",
) -> MoranResult: ...
@dataclass
class MoranResult:
i: float
p_norm: float
z_norm: float
```