2014-06-18 6 views
7

मैट्रिक्स की संख्या अभिव्यक्त किया जा सकता है अगर अग्रिम में नहीं जाना जाता है घटक-वार इसके अलावा करने के लिए सबसे अच्छा तरीका क्या है? अधिक आम तौर पर, के संदर्भ में मैट्रिक्स (या बहु-आयामी सरणी) संचालन करने का कोई अच्छा तरीका है? मैं data.table का उपयोग कई निश्चित चर या डेटा द्वारा डेटा को सॉर्ट करने और समूहित करने में अपनी दक्षता के लिए करता हूं, जिनमें प्रत्येक में अलग-अलग अवलोकन शामिल होते हैं।मैट्रिक्स संचालन और घटक-वार इसके अलावा का उपयोग कर data.table

उदाहरण के लिए:

  1. , डेटा के प्रत्येक अवलोकन (पंक्ति) में दिए गए सदिश घटकों के बाहरी उत्पाद का पता लगाएं प्रत्येक पंक्ति के लिए एक मैट्रिक्स लौटने।
  2. योग जिसके परिणामस्वरूप मैट्रिक्स घटक-वार डेटा श्रेणियों में से प्रत्येक समूह के सभी पंक्तियों पर।

यहाँ 2x2 मैट्रिक्स के साथ सचित्र और केवल एक श्रेणी:

library(data.table) 

# example data, number of rows differs by category t 
N <- 5 
dt <- data.table(t = rep(c("a", "b"), each = 3, len = N), 
       x1 = rep(1:2, len = N), x2 = rep(3:5, len = N), 
       y1 = rep(1:3, len = N), y2 = rep(2:5, len = N)) 
setkey(dt, t) 
> dt 
    t x1 x2 y1 y2 
1: a 1 3 1 2 
2: a 2 4 2 3 
3: a 1 5 3 4 
4: b 2 3 1 5 
5: b 1 4 2 2 

मैं बाहरी उत्पाद पर मैट्रिक्स राशि की गणना करने के लिए एक समारोह का प्रयास किया, %o%

mat_sum <- function(x1, x2, y1, y2){ 
    x <- c(x1, x2) # x vector 
    y <- c(y1, y2) # y vector 
    xy <- x %o% y # outer product (i.e. 2x2 matrix) 
    sum(xy) # <<< THIS RETURNS A SINGLE VALUE, NOT WHAT I WANT. 
    } 

जो, ज़ाहिर है, नहीं है काम क्योंकि sum सरणी में सभी तत्व जोड़ता है।

मैंने this answerReduce('+', .list) का उपयोग करके देखा लेकिन ऐसा लगता है कि सभी मैट्रिक्स के list जोड़े जाने की आवश्यकता है। मैं पता लगा नहीं कि कैसे करना है data.table भीतर है, इसलिए बजाय मैं एक बोझिल काम के आसपास मिल गया है:

# extract each outer product component first... 
mat_comps <- function(x1, x2, y1, y2){ 
    x <- c(x1, x2) # x vector 
    y <- c(y1, y2) # y vector 
    xy <- x %o% y # outer product (i.e. 2x2 matrix) 
    xy11 <- xy[1,1] 
    xy21 <- xy[2,1] 
    xy12 <- xy[1,2] 
    xy22 <- xy[2,2] 
    return(c(xy11, xy21, xy12, xy22)) 
} 

# ...then running this function on dt, 
# taking extra step (making column 'n') to apply it row-by-row... 
dt[, n := 1:nrow(dt)] 
dt[, c("xy11", "xy21", "xy12", "xy22") := as.list(mat_comps(x1, x2, y1, y2)), 
    by = n] 

# ...then sum them individually, now grouping by t 
s <- dt[, list(s11 = sum(xy11), 
       s21 = sum(xy21), 
       s12 = sum(xy12), 
       s22 = sum(xy22)), 
     by = key(dt)] 
> s 
    t s11 s21 s12 s22 
1: a 8 26 12 38 
2: b 4 11 12 23 

और कहा कि इसे यूं घटक है, जो अंत में मैट्रिक्स को वापस परिवर्तित किया जा सकता देता है।

+0

+1 क्या एक महान पहला सवाल। स्टैक ओवरफ़्लो में आपका स्वागत है। –

उत्तर

7

सामान्य तौर पर, data.table कॉलम के साथ काम करने के लिए बनाया गया है। जितना अधिक आप अपनी समस्या को कॉल-वार ऑपरेशंस में बदल देंगे, उतना ही आप data.table से बाहर निकल सकते हैं।

यहाँ इस आपरेशन col-वार को पूरा करने का एक प्रयास है। शायद बेहतर तरीके हैं। समस्या का सामना करने के बारे में एक विचार प्रदान करने के लिए यह एक टेम्पलेट के रूप में अधिक है (भले ही मैं समझता हूं कि यह सभी मामलों में संभव नहीं हो सकता है)।

xcols <- grep("^x", names(dt)) 
ycols <- grep("^y", names(dt)) 
combs <- CJ(ycols, xcols) 
len <- seq_len(nrow(combs)) 
cols = paste("V", len, sep="") 
for (i in len) { 
    c1 = combs$V2[i] 
    c2 = combs$V1[i] 
    set(dt, i=NULL, j=cols[i], value = dt[[c1]] * dt[[c2]]) 
} 

# t x1 x2 y1 y2 V1 V2 V3 V4 
# 1: a 1 3 1 2 1 3 2 6 
# 2: a 2 4 2 3 4 8 6 12 
# 3: a 1 5 3 4 3 15 4 20 
# 4: b 2 3 1 5 2 3 10 15 
# 5: b 1 4 2 2 2 8 2 8 

यह मूलतः बाहरी उत्पाद पर लागू होता है col-वार। अब यह सिर्फ इसे इकट्ठा करने का मामला है।

dt[, lapply(.SD, sum), by=t, .SDcols=cols] 

# t V1 V2 V3 V4 
# 1: a 8 26 12 38 
# 2: b 4 11 12 23 

HTH


संपादित करें: संशोधित cols, c1, c2 थोड़ा V2 और V3 के लिए सही क्रम के साथ उत्पादन प्राप्त करने के लिए।

+0

यहां कई उपयोगी पहलू, विशेष रूप से 'सीजे' और' एसएसडी 'का उपयोग करते हैं, लेकिन 'seq',' grep' और अन्य स्ट्रिंग कमांड जिन्हें मैं पर्याप्त परिचित नहीं था। यह टेम्पलेट सीधे एम-बाय-एन मैट्रिस तक फैला हुआ है, जो आसानी से xcols और ycols से आयामों का उल्लंघन करता है। एक सवाल यह है कि क्यों V2 और V3 को – Scott

+0

उलट दिया गया है, संपादन के लिए धन्यवाद, हालांकि मैं मूल को "गलत" ऑर्डर नहीं करना चाहता हूं। यह केवल 11, 21, 12, 22 सूचीबद्ध मैट्रिक्स तत्वों के आर के डिफ़ॉल्ट कॉल-वार भरने के कारण है। दिलचस्प है कि 'सीजे' इसके विपरीत पंक्ति-वार हो जाता है, जिसे मैं वास्तव में अधिक प्राकृतिक पाता हूं। हो सकता है कि मैं इंडेक्स का ट्रैक रखने में मदद के लिए 'cols <- पेस्ट ("वी", कॉम्ब्स $ V1, कॉम्ब्स $ V2, sep = "") का उपयोग करें। – Scott

2

संपादित करें: "x" और "y" में न केवल 2 तत्वों के लिए, एक संशोधित समारोह हो सकता है:

ff2 = function(x_ls, y_ls) 
{ 
    combs_ls = lapply(seq_along(x_ls[[1]]), 
        function(i) list(sapply(x_ls, "[[", i), 
             sapply(y_ls, "[[", i))) 
    rowSums(sapply(combs_ls, function(x) as.vector(do.call(outer, x)))) 
} 

जहां, "x_ls" और "y_ls" की सूची में हैं संबंधित वैक्टर।

यह का उपयोग करना:

dt[, as.list(ff2(list(x1, x2), list(y1, y2))), by = t] 
# t V1 V2 V3 V4 
#1: a 8 26 12 38 
#2: b 4 11 12 23 

और अन्य "data.frames/टेबल" पर:

set.seed(101) 
DF = data.frame(group = rep(letters[1:3], c(4, 2, 3)), 
       x1 = sample(1:20, 9, T), x2 = sample(1:20, 9, T), 
       x3 = sample(1:20, 9, T), x4 = sample(1:20, 9, T), 
       y1 = sample(1:20, 9, T), y2 = sample(1:20, 9, T), 
       y3 = sample(1:20, 9, T), y4 = sample(1:20, 9, T))    
DT = as.data.table(DF) 

DT[, as.list(ff2(list(x1, x2, x3, x4), 
       list(y1, y2, y3, y4))), by = group] 
# group V1 V2 V3 V4 V5 V6 V7 V8 V9 V10 V11 V12 V13 V14 V15 V16 
#1:  a 338 661 457 378 551 616 652 468 460 773 536 519 416 766 442 532 
#2:  b 108 261 171 99 29 77 43 29 154 386 238 146 161 313 287 121 
#3:  c 345 351 432 293 401 421 425 475 492 558 621 502 510 408 479 492 

मैं नहीं जानता, हालांकि, कैसे "data.table" में एक नहीं होगा स्पष्ट रूप से बताएं कि फ़ंक्शन के अंदर कौन से कॉलम का उपयोग करना है; अर्थात कैसे आप के बराबर कर सकता है:

do.call(rbind, lapply(split(DF[-1], DF$group), 
         function(x) 
          do.call(ff2, c(list(x[grep("^x", names(x))]), 
             list(x[grep("^y", names(x))]))))) 
# [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11] [,12] [,13] [,14] [,15] [,16] 
#a 338 661 457 378 551 616 652 468 460 773 536 519 416 766 442 532 
#b 108 261 171 99 29 77 43 29 154 386 238 146 161 313 287 121 
#c 345 351 432 293 401 421 425 475 492 558 621 502 510 408 479 492 

पुराने उत्तर:

शायद आप की तरह अपने कार्य निर्धारित कर सकते हैं:

ff1 = function(x1, x2, y1, y2) 
    rowSums(sapply(seq_along(x1), 
        function(i) as.vector(c(x1[i], x2[i]) %o% c(y1[i], y2[i])))) 

dt[, as.list(ff1(x1, x2, y1, y2)), by = list(t)] 
# t V1 V2 V3 V4 
#1: a 8 26 12 38 
#2: b 4 11 12 23 
+0

यह स्वच्छ और कॉम्पैक्ट है। एक्स और वाई वैक्टर के मनमाने ढंग से आयामों को समायोजित करने के लिए किसी को फ़ंक्शन (और तर्क) को समायोजित करने की आवश्यकता हो सकती है। – Scott

+0

@ स्कॉट: मैंने अभी जवाब को एक वर्कअराउंड के साथ संपादित किया है, हालांकि मुझे यकीन नहीं है कि यह कितना उपयोगी हो सकता है –

संबंधित मुद्दे