Различные признаки основных компонентов - PullRequest
0 голосов
/ 14 ноября 2018

Я реализовал PCA в Python.Я использовал MNIST-Data и сократил данные до 2d.После этого я использовал KNN для классификации данных.То же самое я повторил с Scikit.В результате у меня с моим PCA точность намного ниже.Я сравнил ПК и вижу, что признаки некоторых компонентов отличаются от результатов SciKit.Я понятия не имею, как это исправить.Надеюсь, один из вас увидит мою ошибку или недоразумение.

class Dimension_reduction:
    def PCA(self, X, dimensions):
        covariance_matrix = self.find_covariance(X)
        eigenvalues, eigenvectors = self.eigenvalue_decomposition(covariance_matrix)
        eigenpairs = self.sort_eigenvalues(eigenvalues, eigenvectors)
        projection_matrix = self.projection_matrix(eigenpairs, dimensions)
        new_featurespace = self.project_reduced_featurespace(X, projection_matrix)
        return new_featurespace

    def find_covariance(self, X):
        means = np.mean(X, axis = 0)
        covariance_matrix = (X - means).T.dot((X - means)) / (len(X)-1)
        return covariance_matrix

    def eigenvalue_decomposition(self, covariance_matrix):
        eigenvalues, eigenvectors = np.linalg.eig(covariance_matrix)
        return eigenvalues, eigenvectors

    def sort_eigenvalues(self, eigenvalues, eigenvectors):
        eigenpairs = [(np.abs(eigenvalues[i]), eigenvectors[:,i]) for i in range(len(eigenvalues))]

        eigenpairs.sort()
        eigenpairs.reverse()

        return eigenpairs

    def projection_matrix(self, eigenpairs, dimensions):
        projection_matrix = np.array(eigenpairs[0][1].reshape(len(eigenpairs[0][1]),1))
        for i in range(1, dimensions, 1):
               projection_matrix = np.concatenate((projection_matrix, 
                                                   np.array(eigenpairs[i][1].reshape(len(eigenpairs[0][1]),1))), axis = 1)
        return projection_matrix

    def project_reduced_featurespace(self, X, projection_matrix):
        return X.dot(projection_matrix)

    def scatter_plot(self, new_X, label_number, labels):
        partial_X = []
        x = []
        y = []
        for i in range(label_number):
            partial_X.append([])
            x.append([])
            y.append([])

        for i in range(len(new_X)):
            label = labels[i]
            partial_X[int(label)].append(new_X[i])
        colors = plt.cm.rainbow(np.linspace(0,1,label_number))

        for i in range(label_number):
            for j in range(len(partial_X[i])):
                x[i].append(partial_X[i][j][0])
                y[i].append(partial_X[i][j][1])
        i = 0
        for x,y,c in zip(x,y, colors):
            plt.scatter(x,y,c, label = str(i))
        return plt, colors

    def eigenfaces(self, X):
        covariance_matrix = self.find_covariance(X)
        eigenvalues, eigenvectors = self.eigenvalue_decomposition(covariance_matrix)
        eigenpairs = self.sort_eigenvalues(eigenvalues, eigenvectors)
        return eigenpairs

Я также использовал разные реализации

def PCA(X):
    PC = []
    cov = np.cov(X.T)
    w,v = np.linalg.eig(cov)
    eig_pairs = [(np.abs(w[i]), v[:,i]) for i in range(len(w))]
    eig_pairs.sort()
    eig_pairs.reverse()
    PC.append(eig_pairs[0][1])
    PC.append(eig_pairs[1][1])
    Y = X.dot(np.array(PC).T)
    return Y

def PCA(data, dims_rescaled_data=2):
    """
    returns: data transformed in 2 dims/columns + regenerated original data
    pass in: data as 2D NumPy array
    """
    import numpy as NP
    from scipy import linalg as LA
    m, n = data.shape
    # mean center the data
    data -= np.mean(data,axis=0)
    # calculate the covariance matrix
    R = NP.cov(data, rowvar=False)
    # calculate eigenvectors & eigenvalues of the covariance matrix
    # use 'eigh' rather than 'eig' since R is symmetric, 
    # the performance gain is substantial
    evals, evecs = LA.eigh(R)
    # sort eigenvalue in decreasing order
    idx = NP.argsort(evals)[::-1]
    evecs = evecs[:,idx]
    # sort eigenvectors according to same index
    evals = evals[idx]
    # select the first n eigenvectors (n is desired dimension
    # of rescaled data array, or dims_rescaled_data)
    evecs = evecs[:, :dims_rescaled_data]
    # carry out the transformation on the data using eigenvectors
    # and return the re-scaled data, eigenvalues, and eigenvectors
    return NP.dot(evecs.T, data.T).T, evals, evecs

def pca_svd(X, num = 2):
    X = X-np.mean(X, axis = 0)
    [u,s,v] = np.linalg.svd(X)
    v = v.T[:,:num]
    return np.dot(X,v)

В сумме есть 4 разных реализации.Результат первого:

# Training
array([[-1.01031446,  6.71282428],
       [-3.03212724,  1.64169381],
       [ 2.95288108, -1.44413258],
       ...,
       [-1.15329784, -2.83978701],
       [-8.02795144,  2.12452378],
       [ 9.83911408,  3.2389573 ]])
# Testing
array([[ 5.15053345,  6.79771421],
       [ 1.84247302, -0.58932415],
       [ 1.66957196,  3.89696398],
       ...,
       [ 5.22253275,  1.74628625],
       [-8.2209684 ,  0.32435677],
       [11.00041468, -4.62978653]])

Для второго:

  #train
    array([[ -4.94267554,  -6.22892054],
           [ -6.96448832,  -1.15779007],
           [ -0.97948   ,   1.92803631],
           ...,
           [ -5.08565892,   3.32369075],
           [-11.96031252,  -1.64062004],
           [  5.906753  ,  -2.75505357]])
    #test
    array([[  1.39046844,   7.2344142 ],
           [ -1.91759199,  -0.15262416],
           [ -2.09049305,   4.33366397],
           ...,
           [  1.46246774,   2.18298624],
           [-11.98103342,   0.76105676],
           [  7.24034966,  -4.19308654]])

Для третьего:

#train
array([[ -4.94267554,  -6.22892054],
       [ -6.96448832,  -1.15779007],
       [ -0.97948   ,   1.92803631],
       ...,
       [ -5.08565892,   3.32369075],
       [-11.96031252,  -1.64062004],
       [  5.906753  ,  -2.75505357]])
#test
array([[-1.39046844,  7.2344142 ],
       [ 1.91759199, -0.15262416],
       [ 2.09049305,  4.33366397],
       ...,
       [-1.46246774,  2.18298624],
       [11.98103342,  0.76105676],
       [-7.24034966, -4.19308654]])

для SVD:

#train
array([[ 4.94267554, -6.22892054],
       [ 6.96448832, -1.15779007],
       [ 0.97948   ,  1.92803631],
       ...,
       [ 5.08565892,  3.32369075],
       [11.96031252, -1.64062004],
       [-5.906753  , -2.75505357]])
#test
xt2

array([[  1.39046844,   7.2344142 ],
       [ -1.91759199,  -0.15262416],
       [ -2.09049305,   4.33366397],
       ...,
       [  1.46246774,   2.18298624],
       [-11.98103342,   0.76105676],
       [  7.24034966,  -4.19308654]])

Наконец-то ПК от scikit:

#train
array([[ 4.9426755 , -6.22891427],
       [ 6.9644884 , -1.15779638],
       [ 0.97948002,  1.92802868],
       ...,
       [ 5.08565916,  3.32364585],
       [11.96031245, -1.64060628],
       [-5.90675305, -2.7550444 ]])
#test
array([[-1.39046854,  7.23440228],
       [ 1.91759194, -0.1526275 ],
       [ 2.09049303,  4.33366458],
       ...,
       [-1.46246766,  2.18299325],
       [11.98103337,  0.76105147],
       [-7.24034972, -4.19309378]])

Видно, что результаты просто по-разному.Но для классификации это проблема.Кроме того, в первом коде должна быть ошибка.Но я не могу его найти.

У кого-нибудь есть идеи?

PS: Если я увеличу количество ПК в проекции, проблема со знаком станет хуже.

...