एक बड़े, विरल मैट्रिक्स पर आयामीता में कमी (SVD या PCA)


31

/ संपादित करें: आगे का अनुसरण करें अब आप irlba :: prcomp_irlba का उपयोग कर सकते हैं


/ संपादित करें: मेरी अपनी पोस्ट पर चल रहा है। irlbaअब "केंद्र" और "पैमाने" तर्क हैं, जो आपको सिद्धांत घटकों की गणना करने के लिए इसका उपयोग करते हैं, उदाहरण के लिए:

pc <- M %*% irlba(M, nv=5, nu=0, center=colMeans(M), right_only=TRUE)$v


मेरे पास एक बड़ी सुविधा है, Matrixजो मैं मशीन लर्निंग एल्गोरिदम में उपयोग करना चाहता हूँ:

library(Matrix)
set.seed(42)
rows <- 500000
cols <- 10000
i <- unlist(lapply(1:rows, function(i) rep(i, sample(1:5,1))))
j <- sample(1:cols, length(i), replace=TRUE)
M <- sparseMatrix(i, j)

क्योंकि इस मैट्रिक्स में कई कॉलम हैं, मैं इसकी आयामीता को कुछ अधिक प्रबंधनीय के रूप में कम करना चाहूंगा। मैं SVD करने के लिए उत्कृष्ट irlba पैकेज का उपयोग कर सकता हूं और पहले n प्रिंसिपल घटकों को वापस कर सकता हूं (5 यहां दिखाया गया है; मैं शायद अपने वास्तविक डेटासेट पर 100 या 500 का उपयोग करूंगा):

library(irlba)
pc <- irlba(M, nu=5)$u

हालाँकि, मैंने पढ़ा है कि PCA करने से पहले, मैट्रिक्स को केंद्र में रखना चाहिए (प्रत्येक स्तंभ से स्तंभ का मतलब घटाएं)। यह मेरे डेटासेट पर करना बहुत मुश्किल है, और इसके अलावा मैट्रिक्स की विरलता को नष्ट कर देगा।

अन-स्केल डेटा पर SVD का प्रदर्शन करना कितना "बुरा" है, और इसे सीधे मशीन लर्निंग एल्गोरिथम में फीड करना है? मैट्रिक्स के स्पार्सिटी को संरक्षित करते हुए क्या मैं इस डेटा को माप सकता हूं?


/ संपादित करें: B_miner द्वारा मेरे ध्यान में लाया गया, "पीसी" वास्तव में होना चाहिए:

pc <- M %*% irlba(M, nv=5, nu=0)$v 

इसके अलावा, मुझे लगता है कि फुलर के उत्तर को crossprodफ़ंक्शन के माध्यम से लागू करना बहुत आसान होना चाहिए , जो विरल मैट्रिस पर बहुत तेज़ है:

system.time(M_Mt <- crossprod(M)) # 0.463 seconds
system.time(means <- colMeans(M)) #0.003 seconds

अब मुझे पूरी तरह से यकीन नहीं है कि meansइससे घटाने से पहले वेक्टर को क्या करना है M_Mt, लेकिन जैसे ही मैं इसका पता लगाऊंगा , पोस्ट कर दूंगा।


/ edit3: यहां प्रक्रिया के प्रत्येक चरण के लिए विरल मैट्रिक्स संचालन का उपयोग करते हुए, व्हीबर कोड का संशोधित संस्करण दिया गया है। यदि आप पूरे विरल मैट्रिक्स को मेमोरी में स्टोर कर सकते हैं, तो यह बहुत जल्दी काम करता है:

library('Matrix')
library('irlba')
set.seed(42)
m <- 500000
n <- 100
i <- unlist(lapply(1:m, function(i) rep(i, sample(25:50,1))))
j <- sample(1:n, length(i), replace=TRUE)
x <- sparseMatrix(i, j, x=runif(length(i)))

n_comp <- 50
system.time({
  xt.x <- crossprod(x)
  x.means <- colMeans(x)
  xt.x <- (xt.x - m * tcrossprod(x.means)) / (m-1)
  svd.0 <- irlba(xt.x, nu=0, nv=n_comp, tol=1e-10)
})
#user  system elapsed 
#0.148   0.030   2.923 

system.time(pca <- prcomp(x, center=TRUE))
#user  system elapsed 
#32.178   2.702  12.322

max(abs(pca$center - x.means))
max(abs(xt.x - cov(as.matrix(x))))
max(abs(abs(svd.0$v / pca$rotation[,1:n_comp]) - 1))

यदि आप स्तंभों की संख्या 10,000 और मूल घटकों की संख्या 25 तक सेट करते हैं, तो- irlbaआधारित पीसीए को 50 अनुमानित प्रमुख घटकों की गणना करने में लगभग 17 मिनट लगते हैं और लगभग 6GB RAM की खपत होती है, जो बहुत बुरा नहीं है।


Zach, जिज्ञासु अगर आप इसे कभी हल किया।
B_Miner

@B_Miner: मूल रूप से, मैं पहले केंद्र या पैमाने पर परेशान किए बिना एसवीडी कर रहा हूं, क्योंकि मैंने अपने स्पार्स मैट्रिक्स को घने मैट्रिक्स में परिवर्तित किए बिना ऐसा करने का एक अच्छा तरीका नहीं पाया है। मूल मैट्रिक्स% *% svd का V घटक "सिद्धांत घटक" देता है। कभी-कभी, मैं बेहतर परिणाम प्राप्त करता हूं यदि मैं "ईजेन वैल्यू" में गुना करता हूं, उदाहरण के लिए v% *% डायग (डी), जहां एसवीडी से ईजेनवेल्यूज का वेक्टर है।
ज़च १

क्या आप v% *% diag (d) को स्वयं या अभी भी मूल मैट्रिक्स X (यानी X% *% v% *% diag (d)) से गुणा करते हैं। ऐसा लगता है कि आप प्रमुख घटक स्कोर के रूप में यू मैट्रिक्स का उपयोग कर रहे हैं?
B_Miner

मैं उपयोग करता हूं X %*% v %*% diag(d, ncol=length(d))। SVD में वी मैट्रिक्स एक के तत्व "रोटेशन" के बराबर है prcompवस्तु, और X %*% vया X %*% v %*% diag(d, ncol=length(d))का प्रतिनिधित्व करता है xएक के तत्व prcompवस्तु। देख लेना stats:::prcomp.default
जैच

हाँ, X% *% v, prcomp से x तत्व है। ऐसा लगता है कि जब आप अपने प्रश्न के अनुसार u मैट्रिक्स का उपयोग करते हैं, तो आप वास्तव में X% *% v% *% diag (1 / d) का उपयोग कर रहे हैं।
B_Miner

जवाबों:


37

सबसे पहले, आप वास्तव में डेटा को केंद्रित करना चाहते हैं । यदि नहीं, तो पीसीए की ज्यामितीय व्याख्या से पता चलता है कि पहला मुख्य घटक साधनों के वेक्टर के करीब होगा और बाद के सभी पीसी इसके लिए ऑर्थोगोनल होंगे, जो उन्हें उस वेक्टर के करीब होने वाले किसी भी पीसी को अनुमान लगाने से रोक देगा। हम उम्मीद कर सकते हैं कि बाद के अधिकांश पीसी लगभग सही हो जाएंगे, लेकिन इसकी कीमत संदिग्ध है जब यह संभव है कि पहले कई पीसी - सबसे महत्वपूर्ण - बहुत गलत होंगे।

इसलिए क्या करना है? पीसीए मैट्रिक्स के एक विलक्षण मूल्य अपघटन के माध्यम से आगे बढ़ता है । आवश्यक जानकारी में निहित होगी , जो इस मामले में बाय मैट्रिक्स है: जो प्रबंधनीय हो सकती है। इसकी गणना में अगले कॉलम के साथ एक कॉलम के डॉट उत्पादों की लगभग 50 मिलियन गणना शामिल है।एक्स एक्स ' 10000 10000XXX1000010000

किसी भी दो कॉलम पर विचार करें, फिर, और (उनमें से प्रत्येक एक -वेक्टर है; इस आयाम को होने दें )। उनके साधन क्रमशः और होने । क्या आप चाहते हैं गणना करने के लिए है, लेखन के लिए के -vector की,जेड ५००००० एन एम वाई एम जेड एन YZ500000nmYmZ1n1

(YmY1)(ZmZ1)=YZmZ1YmY1.Z+mZmY11=YZn(mYmZ),

क्योंकि और ।मीटर जेड = 1जेड / nmY=1Y/nmZ=1Z/n

यह आपको गणना करने के लिए विरल मैट्रिक्स तकनीकों का उपयोग करने की अनुमति देता है , जिनकी प्रविष्टियां के मान प्रदान करती हैं , और फिर स्तंभ साधनों के आधार पर इसके गुणांक को समायोजित करती हैं । समायोजन को चोट नहीं पहुंचनी चाहिए, क्योंकि ऐसा लगता है कि संभावना बहुत कम है। Y जेड 10000 एक्स एक्स 'XXYZ10000XX


उदाहरण

निम्न Rकोड इस दृष्टिकोण को प्रदर्शित करता है। यह एक स्टब का उपयोग करता है get.col, जो बाहरी डेटा स्रोत से एक बार में एक कॉलम को पढ़ सकता है , जिससे आवश्यक मात्रा में रैम की गणना होती है (गणना की गति में कुछ लागत पर, निश्चित रूप से)। यह दो तरीकों से पीसीए की गणना करता है: एसवीडी के माध्यम से पूर्ववर्ती निर्माण पर लागू होता है और सीधे उपयोग करता है । यह तब दो दृष्टिकोणों के आउटपुट की तुलना करता है। गणना का समय 100 स्तंभों के लिए लगभग 50 सेकंड है और लगभग चतुष्कोणीय रूप से तराजू: 10K मैट्रिक्स द्वारा 10K पर SVD करते समय प्रतीक्षा करने के लिए तैयार रहें!Xprcomp

m <- 500000 # Will be 500,000
n <- 100    # will be 10,000
library("Matrix")
x <- as(matrix(pmax(0,rnorm(m*n, mean=-2)), nrow=m), "sparseMatrix")
#
# Compute centered version of x'x by having at most two columns
# of x in memory at any time.
#
get.col <- function(i) x[,i] # Emulates reading a column
system.time({
  xt.x <- matrix(numeric(), n, n)
  x.means <- rep(numeric(), n)
  for (i in 1:n) {
    i.col <- get.col(i)
    x.means[i] <- mean(i.col)
    xt.x[i,i] <- sum(i.col * i.col)
    if (i < n) {
      for (j in (i+1):n) {
        j.col <- get.col(j)
        xt.x[i,j] <- xt.x[j,i] <- sum(j.col * i.col)
      }    
    }
  }
  xt.x <- (xt.x - m * outer(x.means, x.means, `*`)) / (m-1)
  svd.0 <- svd(xt.x / m)
}
)
system.time(pca <- prcomp(x, center=TRUE))
#
# Checks: all should be essentially zero.
#
max(abs(pca$center - x.means))
max(abs(xt.x - cov(x)))
max(abs(abs(svd.0$v / pca$rotation) - 1)) # (This is an unstable calculation.)

विस्तृत उत्तर के लिए धन्यवाद। इसका एक फायदा irlbaयह है कि आप nuएल्गोरिथ्म को पहले n सिद्धांत घटकों तक सीमित करने के लिए निर्दिष्ट कर सकते हैं , जिससे यह प्रभावकारिता बहुत बढ़ जाती है और (मुझे लगता है) XX 'मैट्रिक्स की गणना को दरकिनार कर देता है।
Zach

1
लेकिन आप किसके साथ काम करना चाहते हैं? गुणांक वाले मैट्रिक्स द्वारा एक विरल जो कि उस समस्या का प्रतिनिधित्व नहीं करता है जिसे आपको हल करने की आवश्यकता है, या द्वारा गुणांक के साथ जो उस समस्या का प्रतिनिधित्व करता है जिसे आप हल करना चाहते हैं? वैसे भी पहले कुछ प्रमुख घटकों को प्राप्त करने के लिए उत्तरार्द्ध पर लागू किया जा सकता है, इसलिए आपको दोनों दुनिया के सर्वश्रेष्ठ मिलते हैं। 500000 5 × 10 9 10000 10000 10 8100005000005×1091000010000108irlba
whuber

मुझे लगता है कि बाद में। =)। इसलिए मुझे अपने विरल मैट्रिक्स में स्तंभों के प्रत्येक जोड़े के लिए डॉट उत्पाद की गणना करने की आवश्यकता है, डॉट उत्पाद colMeansमैट्रिक्स से विरल मैट्रिक्स को घटाएं, फिर परिणाम पर irlba चलाएं?
Zach

लगभग: ध्यान दें कि आप स्तंभ के उत्पादों को घटा रहे हैं, न कि स्तंभ का अर्थ है स्वयं। एल्गोरिथ्म का आपका सूत्रीकरण अन्यथा उत्कृष्ट है, क्योंकि यद्यपि आप गणना कर रहे हैं , आप मैट्रिक्स गुणा करने के लिए वास्तव में नहीं बनाना चाहते हैं । इसके बजाय, यदि RAM वास्तव में सीमित है, तो आप एक समय में कॉलम के सबसेट में पढ़कर बैचों में कॉलम डॉट उत्पादों का प्रदर्शन कर सकते हैं। यह पहले से अधिक छोटे matrices के साथ प्रयोग करने के लिए बुद्धिमान होगा :-)। X XXRX
whuber

5
मैंने चित्रण करने के लिए कोड जोड़ा।
whuber
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.