EMD分解python代码
时间: 2023-07-02 14:07:04 浏览: 265
EMD(Earth Mover's Distance)是一种衡量两个概率分布相似度的方法。其核心思想是将一个分布通过一系列步骤转化为另一个分布,每个步骤都有一个成本,最终计算所有步骤的成本之和作为两个分布的距离。
下面是使用Python实现EMD分解的代码:
```python
import numpy as np
def emd(distribution1, distribution2, cost_matrix):
# 计算两个分布的累积分布函数
cdf1 = np.cumsum(distribution1)
cdf2 = np.cumsum(distribution2)
# 初始化一个全零的流量矩阵
flow = np.zeros(cost_matrix.shape)
# 当前分布的累积质量和
mass1 = 0
mass2 = 0
# 遍历所有的成本矩阵元素
for i in range(cost_matrix.shape[0]):
for j in range(cost_matrix.shape[1]):
# 如果已经有流量了,跳过
if flow[i,j] > 0:
continue
# 计算从i到j的最小成本路径
path_cost, path = find_path(cost_matrix, flow, cdf1, cdf2, i, j)
# 计算沿该路径的最大可用流量
max_flow = min(distribution1[path[0]] - mass1, distribution2[path[-1]] - mass2)
# 在路径上增加流量
for k in range(len(path)-1):
flow[path[k], path[k+1]] += max_flow
# 更新累积质量和
mass1 += max_flow
mass2 += max_flow
# 如果已经匹配完毕,跳出循环
if mass1 == np.sum(distribution1) and mass2 == np.sum(distribution2):
break
# 计算总成本
total_cost = np.sum(flow * cost_matrix)
return total_cost, flow
def find_path(cost_matrix, flow, cdf1, cdf2, i, j):
# 计算从i到j的路径成本
path_cost = cost_matrix[i,j] + cdf1[i] - cdf1[j] - cdf2[j] + cdf2[i]
# 如果路径成本为0,说明已经达到最优解
if path_cost == 0:
return 0, [i, j]
# 初始化一个队列,用于广度优先搜索
queue = [(i, j)]
# 初始化一组空间,用于记录路径
path_set = {(i, j): []}
# 开始广度优先搜索
while len(queue) > 0:
# 弹出队列中的第一个元素
curr = queue.pop(0)
# 遍历所有可能的下一步
for next_node in get_next_nodes(curr, cost_matrix.shape[0], cost_matrix.shape[1]):
# 如果没有增广路,跳过
if flow[next_node] >= 1:
continue
# 计算到下一个节点的路径成本
next_cost = cost_matrix[curr] + cdf1[curr[0]] - cdf1[next_node[0]] - cdf2[next_node[1]] + cdf2[curr[1]]
# 如果路径成本相等,将节点加入队列中
if next_cost == path_cost:
queue.append(next_node)
path_set[next_node] = path_set[curr] + [next_node]
# 返回最小成本路径及其成本
return path_cost, path_set[(i, j)]
def get_next_nodes(node, n_rows, n_cols):
# 计算下一个节点可能的坐标
next_nodes = []
if node[0] < n_rows - 1:
next_nodes.append((node[0]+1, node[1]))
if node[0] > 0:
next_nodes.append((node[0]-1, node[1]))
if node[1] < n_cols - 1:
next_nodes.append((node[0], node[1]+1))
if node[1] > 0:
next_nodes.append((node[0], node[1]-1))
return next_nodes
```
该代码实现了EMD分解算法的核心逻辑。其中,emd函数接受两个分布和一个成本矩阵作为输入,计算两个分布之间的EMD距离和最优的流量矩阵。主要步骤包括计算累积分布函数、初始化流量矩阵、遍历成本矩阵、查找最小成本路径、更新流量矩阵、计算总成本等。find_path函数实现了广度优先搜索查找最小成本路径的逻辑,get_next_nodes函数计算一个节点可能的下一步坐标。
阅读全文