2015-11-04 17 views
5

Tôi đang cố gắng tính toán 2 thành phần chính chính từ tập dữ liệu trong C++ với Eigen.Phân tích thành phần chính với Thư viện Eigen

Cách tôi thực hiện tại thời điểm này là chuẩn hóa dữ liệu giữa [0, 1] và sau đó căn giữa giá trị trung bình. Sau đó tôi tính toán ma trận hiệp phương sai và chạy phân tách giá trị riêng trên đó. Tôi biết SVD nhanh hơn, nhưng tôi nhầm lẫn về các thành phần được tính toán.

Đây là mã lớn về cách tôi làm điều đó (nơi traindata là MxN ma trận có kích thước đầu vào của tôi):

Eigen::VectorXf normalize(Eigen::VectorXf vec) { 
    for (int i = 0; i < vec.size(); i++) { // normalize each feature. 
     vec[i] = (vec[i] - minCoeffs[i])/scalingFactors[i]; 
    } 
    return vec; 
} 

// Calculate normalization coefficients (globals of type Eigen::VectorXf). 
maxCoeffs = traindata.colwise().maxCoeff(); 
minCoeffs = traindata.colwise().minCoeff(); 
scalingFactors = maxCoeffs - minCoeffs; 

// For each datapoint. 
for (int i = 0; i < traindata.rows(); i++) { // Normalize each datapoint. 
    traindata.row(i) = normalize(traindata.row(i)); 
} 

// Mean centering data. 
Eigen::VectorXf featureMeans = traindata.colwise().mean(); 
Eigen::MatrixXf centered = traindata.rowwise() - featureMeans; 

// Compute the covariance matrix. 
Eigen::MatrixXf cov = centered.adjoint() * centered; 
cov = cov/(traindata.rows() - 1); 

Eigen::SelfAdjointEigenSolver<Eigen::MatrixXf> eig(cov); 
// Normalize eigenvalues to make them represent percentages. 
Eigen::VectorXf normalizedEigenValues = eig.eigenvalues()/eig.eigenvalues().sum(); 


// Get the two major eigenvectors and omit the others. 
Eigen::MatrixXf evecs = eig.eigenvectors(); 
Eigen::MatrixXf pcaTransform = evecs.rightCols(2); 


// Map the dataset in the new two dimensional space. 
traindata = traindata * pcaTransform; 

Kết quả của mã này là một cái gì đó như thế này:

enter image description here

Để xác nhận kết quả của tôi, tôi đã thử cùng với WEKA. Vì vậy, những gì tôi đã làm là sử dụng bình thường hóa và bộ lọc trung tâm, theo thứ tự này. Sau đó, bộ lọc thành phần chính và lưu + vẽ đầu ra. Kết quả là thế này:

enter image description here

Về mặt kỹ thuật tôi nên đã làm điều tương tự, tuy nhiên kết quả là rất khác nhau. Có ai có thể thấy nếu tôi phạm sai lầm không?

+0

Một điều cần thêm: Tôi khá chắc chắn rằng WEKA đang sử dụng SVD. Nhưng điều này không nên giải thích sự khác biệt trong kết quả hay? – Chris

Trả lời

1

Lý do là Weka tiêu chuẩn hóa tập dữ liệu. Điều này có nghĩa là nó quy mô phương sai của từng tính năng cho phương sai đơn vị. Khi tôi làm điều này, các ô trông giống nhau. Về mặt kỹ thuật, cách tiếp cận của tôi cũng chính xác.

+0

bạn có thể vui lòng đăng mã đang chạy không? Cảm ơn. –

+0

Tôi sẽ xem xét, tôi không biết liệu tôi vẫn có quyền truy cập vào đoạn mã đó và phiên bản nào tôi đã sử dụng cuối cùng chưa. Nhưng tôi chắc chắn đã nói về tiêu chuẩn hóa cổ điển, được xác định rõ: https://en.wikipedia.org/wiki/Feature_scaling#Standardization – Chris

4

Khi chia tỷ lệ thành 0,1, bạn sửa đổi biến cục bộ vec nhưng quên cập nhật traindata.

Hơn nữa, điều này có thể được thực hiện dễ dàng hơn theo cách này:

RowVectorXf minCoeffs = traindata.colwise().maxCoeff(); 
RowVectorXf minCoeffs = traindata.colwise().minCoeff(); 
RowVectorXf scalingFactors = maxCoeffs - minCoeffs; 
traindata = (traindata.rowwise()-minCoeffs).array().rowwise()/scalingFactors.array(); 

có nghĩa là, sử dụng hàng-vectơ và mảng tính năng.

Hãy để tôi cũng thêm rằng phân tách tỷ lệ riêng biệt đối xứng thực sự nhanh hơn SVD. Lợi thế thực sự của SVD trong trường hợp này là nó tránh việc bình phương các mục nhập, nhưng vì dữ liệu đầu vào của bạn được chuẩn hóa và căn giữa và bạn chỉ quan tâm đến các giá trị riêng lớn nhất, không có mối quan tâm chính xác ở đây.

+0

Đó là một sai lầm, trong mã lớn của tôi, tôi đã thực hiện một cuộc gọi funciton trả về bằng giá trị như thế này: traindata.row (i) = normalize (traindata.row (i)) ;. Thay đổi nó ở đây quá để đảm bảo không có sai lầm. Cảm ơn bạn đã đơn giản hóa mã, tôi đoán nó bằng cách nào đó có thể. Bạn có thấy vấn đề khác không? – Chris

+0

Một câu hỏi khác, trình biên dịch của tôi cho tôi biết 'không phù hợp với' nhà điều hành '/' khi tôi chạy mã của bạn. Tôi có Eigen3, dường như không có sự phân chia theo hàng hoặc? – Chris

+0

điều này sẽ ném phân chia bằng không nếu bạn có cho 1 tính năng max = min, tôi có đúng không? –

Các vấn đề liên quan