Merci beaucoup amibe pour la compréhension des poids des rangées. Je sais que ce n'est pas un stackoverflow, mais j'ai eu quelques difficultés à trouver une implémentation de PCA pondérée par ligne avec explication et, puisque c'est l'un des premiers résultats lors de la recherche de PCA pondéré, j'ai pensé qu'il serait bon d'attacher ma solution , cela peut peut-être aider d'autres personnes dans la même situation. Dans cet extrait de code Python2, une PCA pondérée avec un noyau RBF comme celui décrit ci-dessus est utilisée pour calculer les tangentes d'un ensemble de données 2D. Je serai très heureux d'entendre des commentaires!
def weighted_pca_regression(x_vec, y_vec, weights):
"""
Given three real-valued vectors of same length, corresponding to the coordinates
and weight of a 2-dimensional dataset, this function outputs the angle in radians
of the line that aligns with the (weighted) average and main linear component of
the data. For that, first a weighted mean and covariance matrix are computed.
Then u,e,v=svd(cov) is performed, and u * f(x)=0 is solved.
"""
input_mat = np.stack([x_vec, y_vec])
weights_sum = weights.sum()
# Subtract (weighted) mean and compute (weighted) covariance matrix:
mean_x, mean_y = weights.dot(x_vec)/weights_sum, weights.dot(y_vec)/weights_sum
centered_x, centered_y = x_vec-mean_x, y_vec-mean_y
matrix_centered = np.stack([centered_x, centered_y])
weighted_cov = matrix_centered.dot(np.diag(weights).dot(matrix_centered.T)) / weights_sum
# We know that v rotates the data's main component onto the y=0 axis, and
# that u rotates it back. Solving u.dot([x,0])=[x*u[0,0], x*u[1,0]] gives
# f(x)=(u[1,0]/u[0,0])x as the reconstructed function.
u,e,v = np.linalg.svd(weighted_cov)
return np.arctan2(u[1,0], u[0,0]) # arctan more stable than dividing
# USAGE EXAMPLE:
# Define the kernel and make an ellipse to perform regression on:
rbf = lambda vec, stddev: np.exp(-0.5*np.power(vec/stddev, 2))
x_span = np.linspace(0, 2*np.pi, 31)+0.1
data_x = np.cos(x_span)[:-1]*20-1000
data_y = np.sin(x_span)[:-1]*10+5000
data_xy = np.stack([data_x, data_y])
stddev = 1 # a stddev of 1 in this context is highly local
for center in data_xy.T:
# weight the points based on their euclidean distance to the current center
euclidean_distances = np.linalg.norm(data_xy.T-center, axis=1)
weights = rbf(euclidean_distances, stddev)
# get the angle for the regression in radians
p_grad = weighted_pca_regression(data_x, data_y, weights)
# plot for illustration purposes
line_x = np.linspace(-5,5,10)
line_y = np.tan(p_grad)*line_x
plt.plot(line_x+center[0], line_y+center[1], c="r")
plt.scatter(*data_xy)
plt.show()
Et un exemple de sortie (il fait de même pour chaque point):
Santé,
Andres