[英]How to implement a 2D Gaussian on a 2D numpy array
我有一個大小為 10 x 10 的二維 NumPy 數組,我試圖在其中實現二維高斯分布,以便我可以將新列用作我的 ML model 中的一個特征。中心(高斯分布的峰值) 應該位於二維 NumPy 數組的 (3, 5) 處。 Python有什么辦法嗎? 我還包含了我的 np 數組的熱圖。 我感謝任何反饋! 新年快樂!
這是我的數據:
import numpy as np
import matplotlib.pyplot as plt
from scipy.stats import multivariate_normal
my_np_list = [310.90634 , 287.137 , 271.87973 , 266.6 , 271.87973 ,
287.137 , 310.90634 , 341.41458 , 377.02936 , 416.44254 ,
266.6 , 238.4543 , 219.844 , 213.28001 , 219.844 ,
238.4543 , 266.6 , 301.62347 , 341.41458 , 384.496 ,
226.2176 , 192.248 , 168.61266 , 159.96 , 168.61266 ,
192.248 , 226.2176 , 266.6 , 310.90634 , 357.68146 ,
192.248 , 150.81174 , 119.22715 , 106.64001 , 119.22715 ,
150.81174 , 192.248 , 238.4543 , 287.137 , 337.2253 ,
168.61266 , 119.22715 , 75.40587 , 53.320004, 75.40587 ,
119.22715 , 168.61266 , 219.844 , 271.87973 , 324.33292 ,
159.96 , 106.64001 , 53.320004, 0. , 53.320004,
106.64001 , 159.96 , 213.28001 , 266.6 , 319.92 ,
168.61266 , 119.22715 , 75.40587 , 53.320004, 75.40587 ,
119.22715 , 168.61266 , 219.844 , 271.87973 , 324.33292 ,
192.248 , 150.81174 , 119.22715 , 106.64001 , 119.22715 ,
150.81174 , 192.248 , 238.4543 , 287.137 , 337.2253 ,
226.2176 , 192.248 , 168.61266 , 159.96 , 168.61266 ,
192.248 , 226.2176 , 266.6 , 310.90634 , 357.68146 ,
266.6 , 238.4543 , 219.844 , 213.28001 , 219.844 ,
238.4543 , 266.6 , 301.62347 , 341.41458 , 384.496 ]
my_np_array = np.array(my_np_list).reshape(10, 10)
plt.imshow(my_np_array, interpolation='none')
plt.show()
size = 100
store_center = (3, 5)
i_center = 3
j_center = 5
我在我的陣列上嘗試了 scipy.stats.multivariate_normal.pdf,但它沒有用。
import scipy
from scipy import stats
my_np_array = my_np_array.reshape(-1)
y = scipy.stats.multivariate_normal.pdf(my_np_array, mean=2, cov=0.5)
y = y.reshape(10,10)
yy = np.dot(y.T,y)
如果我正確理解你的問題,你想計算一個二維高斯 PDF 與你在my_np_array
中的數據具有相同的形狀(例如 10 x 10)。 您當前的代碼僅在將其重塑為一維時計算一維分布,並且僅包括一個均值和 cov。 相反,嘗試創建一個索引值網格(所有 i、j 對)並分別使用i_center
和j_center
作為沿i
和j
維度分布的兩個平均值,如下所示:
import numpy as np
import matplotlib.pyplot as plt
from scipy.stats import multivariate_normal
my_np_list = [310.90634 , 287.137 , 271.87973 , 266.6 , 271.87973 ,
287.137 , 310.90634 , 341.41458 , 377.02936 , 416.44254 ,
266.6 , 238.4543 , 219.844 , 213.28001 , 219.844 ,
238.4543 , 266.6 , 301.62347 , 341.41458 , 384.496 ,
226.2176 , 192.248 , 168.61266 , 159.96 , 168.61266 ,
192.248 , 226.2176 , 266.6 , 310.90634 , 357.68146 ,
192.248 , 150.81174 , 119.22715 , 106.64001 , 119.22715 ,
150.81174 , 192.248 , 238.4543 , 287.137 , 337.2253 ,
168.61266 , 119.22715 , 75.40587 , 53.320004, 75.40587 ,
119.22715 , 168.61266 , 219.844 , 271.87973 , 324.33292 ,
159.96 , 106.64001 , 53.320004, 0. , 53.320004,
106.64001 , 159.96 , 213.28001 , 266.6 , 319.92 ,
168.61266 , 119.22715 , 75.40587 , 53.320004, 75.40587 ,
119.22715 , 168.61266 , 219.844 , 271.87973 , 324.33292 ,
192.248 , 150.81174 , 119.22715 , 106.64001 , 119.22715 ,
150.81174 , 192.248 , 238.4543 , 287.137 , 337.2253 ,
226.2176 , 192.248 , 168.61266 , 159.96 , 168.61266 ,
192.248 , 226.2176 , 266.6 , 310.90634 , 357.68146 ,
266.6 , 238.4543 , 219.844 , 213.28001 , 219.844 ,
238.4543 , 266.6 , 301.62347 , 341.41458 , 384.496 ]
my_np_array = np.array(my_np_list).reshape(10, 10)
plt.imshow(my_np_array, interpolation='none')
plt.show()
i_center = 3
j_center = 5
# Create grid of i, j points
# See https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.multivariate_normal.html
j_n, i_n = my_np_array.shape
j_grid, i_grid = np.mgrid[0:j_n, 0:i_n]
pos = np.dstack((j_grid, i_grid))
# Create 2D Gaussian PDF values for grid
rv = multivariate_normal([j_center, i_center], [[0.5, 0], [0, 0.5]])
y = rv.pdf(pos)
# Plot 2D PDF values
plt.imshow(y, interpolation='none')
plt.show()
pdf 在pos
中的所有 j 和 i 對上進行評估, j_center
和i_center
值提供 position,其中出現二維高斯分布中的峰值(即平均值)。 cov
矩陣只有對角線填充了您提供的值,因為它看起來像您希望基於數據的對稱,但您可以使用非對角線值來查看會發生什么。
這是最適合的 2-Gaussian。
import numpy as np
import matplotlib.pyplot as plt
import scipy.optimize
my_np_list = [
310.90634 , 287.137 , 271.87973 , 266.6 , 271.87973 ,
287.137 , 310.90634 , 341.41458 , 377.02936 , 416.44254 ,
266.6 , 238.4543 , 219.844 , 213.28001 , 219.844 ,
238.4543 , 266.6 , 301.62347 , 341.41458 , 384.496 ,
226.2176 , 192.248 , 168.61266 , 159.96 , 168.61266 ,
192.248 , 226.2176 , 266.6 , 310.90634 , 357.68146 ,
192.248 , 150.81174 , 119.22715 , 106.64001 , 119.22715 ,
150.81174 , 192.248 , 238.4543 , 287.137 , 337.2253 ,
168.61266 , 119.22715 , 75.40587 , 53.320004, 75.40587 ,
119.22715 , 168.61266 , 219.844 , 271.87973 , 324.33292 ,
159.96 , 106.64001 , 53.320004, 0. , 53.320004,
106.64001 , 159.96 , 213.28001 , 266.6 , 319.92 ,
168.61266 , 119.22715 , 75.40587 , 53.320004, 75.40587 ,
119.22715 , 168.61266 , 219.844 , 271.87973 , 324.33292 ,
192.248 , 150.81174 , 119.22715 , 106.64001 , 119.22715 ,
150.81174 , 192.248 , 238.4543 , 287.137 , 337.2253 ,
226.2176 , 192.248 , 168.61266 , 159.96 , 168.61266 ,
192.248 , 226.2176 , 266.6 , 310.90634 , 357.68146 ,
266.6 , 238.4543 , 219.844 , 213.28001 , 219.844 ,
238.4543 , 266.6 , 301.62347 , 341.41458 , 384.496 ,
]
my_np_array = np.array(my_np_list).reshape(10, -1)
def gaussian2(xy: np.ndarray, a: float, b: float, c: float, d: float, e: float, f: float) -> np.ndarray:
x, y = xy
z = (
a - b
* np.exp(-((x - c)/d)**2)
* np.exp(-((y - e)/f)**2)
)
return z
xy = np.stack(
np.meshgrid(
np.arange(my_np_array.shape[1]),
np.arange(my_np_array.shape[0]),
)
).reshape((2, -1))
param, _ = scipy.optimize.curve_fit(
f=gaussian2,
xdata=xy,
ydata=my_np_array.ravel(),
p0=(400, 400,
3, 1,
5, 1)
)
print(param)
zfit = gaussian2(xy, *param).reshape(my_np_array.shape)
fig, (ax_act, ax_fit) = plt.subplots(nrows=1, ncols=2)
ax_act.imshow(my_np_array)
ax_fit.imshow(zfit)
plt.show()
[447.47305265 394.42329346 3.02857599 5.53214092 4.98984104
5.56048623]
它太寬泛了,所以如果你想要更好的擬合,你需要使用非高斯的東西。 例如,大約 1.7 和 1.8 的修改后的指數提供了一個很好的擬合 - 打折你的峰值“0”,這在我看來是假的。
def gaussian2(xy: np.ndarray, a: float, b: float, c: float, d: float, e: float, f: float, g: float, h: float) -> np.ndarray:
x, y = xy
z = (
a - b
* np.exp(-np.abs((x - c)/d)**e)
* np.exp(-np.abs((y - f)/g)**h)
)
return z
param, _ = scipy.optimize.curve_fit(
f=gaussian2,
xdata=xy,
ydata=my_np_array.ravel(),
p0=(400, 400,
3, 5, 2,
5, 5, 2)
)
[482.96976151 441.22504655 3.01091214 6.11061124 1.79338408
5.00625763 6.27235212 1.69061652]
如果您從擬合中排除假峰,這將進一步改善:
z_flat = my_np_array.ravel()
not_zero, = np.nonzero(z_flat)
z_flat = z_flat[not_zero]
xy = xy[:, not_zero]
# ...
zfit = np.zeros_like(my_np_array)
x, y = xy
zfit[y, x] = gaussian2(xy, *param)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.