2012-05-19 9 views
15

मैं एक नया डेटा फ्रेम बनाने के लिए apply या संबंधित फ़ंक्शन का उपयोग कैसे कर सकता हूं जिसमें बहुत अधिक डेटा फ्रेम में कॉलम की प्रत्येक जोड़ी के औसत औसत के परिणाम शामिल हैं?कॉलम के समूह पर एक फ़ंक्शन लागू करें

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

एक सरल उदाहरण के लिए, दो नमूनों पर तीन को दोहराने माप, मैं कैसे एक डेटा फ्रेम कि दो कॉलम (नमूना प्रति एक) है, एक औसत dat$a में replicates की प्रत्येक पंक्ति है कि, dat$b के साथ समाप्त कर सकते हैं साथ और dat$c और dat$d, dat$e और dat$f के लिए प्रत्येक पंक्ति का औसत है।

यहाँ कुछ उदाहरण डेटा

dat <- data.frame(a = rnorm(16), b = rnorm(16), c = rnorm(16), d = rnorm(16), e = rnorm(16), f = rnorm(16)) 

      a   b   c   d   e   f 
1 -0.9089594 -0.8144765 0.872691548 0.4051094 -0.09705234 -1.5100709 
2 0.7993102 0.3243804 0.394560355 0.6646588 0.91033497 2.2504104 
3 0.2963102 -0.2911078 -0.243723116 1.0661698 -0.89747522 -0.8455833 
4 -0.4311512 -0.5997466 -0.545381175 0.3495578 0.38359390 0.4999425 
5 -0.4955802 1.8949285 -0.266580411 1.2773987 -0.79373386 -1.8664651 
6 1.0957793 -0.3326867 -1.116623982 -0.8584253 0.83704172 1.8368212 
7 -0.2529444 0.5792413 -0.001950741 0.2661068 1.17515099 0.4875377 
8 1.2560402 0.1354533 1.440160168 -2.1295397 2.05025701 1.0377283 
9 0.8123061 0.4453768 1.598246016 0.7146553 -1.09476532 0.0600665 
10 0.1084029 -0.4934862 -0.584671816 -0.8096653 1.54466019 -1.8117459 
11 -0.8152812 0.9494620 0.100909570 1.5944528 1.56724269 0.6839954 
12 0.3130357 2.6245864 1.750448404 -0.7494403 1.06055267 1.0358267 
13 1.1976817 -1.2110708 0.719397607 -0.2690107 0.83364274 -0.6895936 
14 -2.1860098 -0.8488031 -0.302743475 -0.7348443 0.34302096 -0.8024803 
15 0.2361756 0.6773727 1.279737692 0.8742478 -0.03064782 -0.4874172 
16 -1.5634527 -0.8276335 0.753090683 2.0394865 0.79006103 0.5704210 

मैं इस

  X1   X2 
1 -0.28358147 -0.40067128 
2 0.50608365 1.27513471 
3 -0.07950691 -0.22562957 
4 -0.52542633 0.41103139 
5 0.37758930 -0.46093340 
6 -0.11784382 0.60514586 
7 0.10811540 0.64293184 
8 0.94388455 0.31948189 
9 0.95197629 -0.10668118 
10 -0.32325169 -0.35891702 
11 0.07836345 1.28189698 
12 1.56269017 0.44897971 
13 0.23533617 -0.04165384 
14 -1.11251880 -0.39810121 
15 0.73109533 0.11872758 
16 -0.54599850 1.13332286 

जो मैं इस के साथ किया था की तरह कुछ के बाद कर रहा हूँ है, लेकिन स्पष्ट रूप से मेरी बहुत बड़ा डेटा फ्रेम के लिए अच्छा नहीं है ...

data.frame(cbind(
apply(cbind(dat$a, dat$b, dat$c), 1, mean), 
apply(cbind(dat$d, dat$e, dat$f), 1, mean) 
)) 

मैंने apply और लूप की कोशिश की है और इसे काफी मिल नहीं सकता है। मेरे वास्तविक डेटा में कुछ सैकड़ों कॉलम हैं।

+0

क्या यह हमेशा हर तीन कॉलम है? क्या आप नामों के वेक्टर या इंडेक्स के वेक्टर के वेक्टर का वेक्टर खिला रहे हैं? यदि उपयोगकर्ता उपयोगकर्ता 1317221_G का उत्तर वह नहीं है जो आप शायद बाद में आपको अधिक जानकारी देने की आवश्यकता है। –

+1

वंशावली के लिए, उपरोक्त प्रश्न पंक्तियों के समूहों (और कुछ अलग दृष्टिकोण हैं) के लिए एक फ़ंक्शन लागू करने के बारे में इस हालिया प्रश्न का हस्तांतरण प्रतीत होता है: http://stackoverflow.com/q/10837258/1036500 – Ben

उत्तर

14

यह है कि में अपनी स्थिति को और अधिक generalizable हो सकता है आप सूचकांकों की एक सूची गुजरती हैं। गति एक समस्या (बड़े डेटा फ्रेम) है, तो मैं do.call बजाय sapply साथ lapply के लिए चुनते हैं:

x <- list(c('a','b','c'), c('d', 'e', 'f')) 
do.call(cbind, lapply(x, function(i) rowMeans(dat[, i]))) 

संपादित

:

x <- list(1:3, 4:6) 
do.call(cbind, lapply(x, function(i) rowMeans(dat[, i]))) 

वर्क्स अगर आप अभी भी col नाम है

बस ऐसा लगता है कि आप इसे हर तीन कॉलम करने के लिए स्वचालित करना चाहते हैं।मैं वहाँ एक बेहतर तरीका है पता है, लेकिन यहाँ यह एक 100 स्तंभ डेटा सेट पर है:

dat <- data.frame(matrix(rnorm(16*100), ncol=100)) 

n <- 1:ncol(dat) 
ind <- matrix(c(n, rep(NA, 3 - ncol(dat)%%3)), byrow=TRUE, ncol=3) 
ind <- data.frame(t(na.omit(ind))) 
do.call(cbind, lapply(ind, function(i) rowMeans(dat[, i]))) 

संपादित 2 फिर भी अनुक्रमण से खुश नहीं। मुझे लगता है कि इंडेक्स को पास करने के लिए एक बेहतर/तेज़ तरीका है। यहां विधि संतोषजनक नहीं है, हालांकि एक दूसरे है:

n <- 1:ncol(dat) 
ind <- data.frame(matrix(c(n, rep(NA, 3 - ncol(dat)%%3)), byrow=F, nrow=3)) 
nonna <- sapply(ind, function(x) all(!is.na(x))) 
ind <- ind[, nonna] 

do.call(cbind, lapply(ind, function(i)rowMeans(dat[, i]))) 
+1

यह अंतिम कॉलम छोड़ देता है क्योंकि इसमें एक साथ बांधने के लिए तीन कॉलम नहीं होते हैं। –

+0

हां, आपका संपादन वही करता है जो मैं खोज रहा हूं, बहुत बहुत धन्यवाद। क्षमा करें कि मेरा प्रश्न खराब गठित किया गया था, यह कुछ लंबे समय तक निष्फल प्रयासों से पैदा हुआ था ... – Ben

+1

मैं सूचकांक बनाने और यहां वापस लिंक करने के लिए एक बेहतर तरीका मांगने जा रहा हूं। –

7

, वैक्टर ए, बी से पंक्तियों के लिए मतलब ग

rowMeans(dat[1:3]) 

सब एक कॉल में, से वैक्टर डी, ई पंक्तियों के लिए इसका मतलब है च

rowMeans(dat[4:6]) 

आप

results<-cbind(rowMeans(dat[1:3]),rowMeans(dat[4:6])) 
मिल

यदि आप केवल कॉलम के नाम जानते हैं और ऑर्डर नहीं करते हैं तो आप इसका उपयोग कर सकते हैं:

rowMeans(cbind(dat["a"],dat["b"],dat["c"])) 
rowMeans(cbind(dat["d"],dat["e"],dat["f"])) 

#I dont know how much damage this does to speed but should still be quick 
+0

और इसके बारे में क्या सैकड़ों कॉलम के साथ डेटा फ्रेम के लिए? आप इसे कैसे सामान्य कर सकते हैं? – Ben

+0

@ जोरन, आप सही हैं, मैं अपने प्रश्न की तैयारी में बहुत जल्दबाजी में था, अस्पष्टता के लिए खेद है। टायलर रिंकर के संपादन में कोड है जो मैं करता हूं। – Ben

5

rowMeans समाधान तेजी से होगा, लेकिन पूर्णता इस तरीके से apply के साथ ऐसा कर सकता है:

t(apply(dat,1,function(x){ c(mean(x[1:3]),mean(x[4:6])) })) 
+1

पंक्ति के बारे में डेटा फ्रेम में तीन कॉलम के लगातार सेट के लिए कितने सौ कॉलम हैं? – Ben

+2

@Ben इसे किसी समस्या से कम करें जिसे आपने पहले ही हल कर लिया है: (1) ट्रांसफर (2) ** plyr ** या ** data.table ** का उपयोग करें, (3) वापस स्थानांतरित करें। (मान लीजिए सबकुछ संख्यात्मक है।) – joran

+0

मैं इसे एक शॉट दूंगा और देख सकता हूं कि क्या मैं कुछ और कुशलता से आ सकता हूं कि टायलर का समाधान ऊपर है (संभावना नहीं है, लेकिन कोशिश करने लायक है!) – Ben

2

@ Joran के सुझाव से प्रेरित होकर मैं इस के साथ आया था (वास्तव में वह क्या सुझाव से थोड़ी अलग है, हालांकि सुर सुझाव विशेष रूप से उपयोगी था):

एक बनाओ p कॉलम के साथ उदाहरण डेटा की डेटा फ्रेम एक यथार्थवादी डेटा सेट अनुकरण (निम्नलिखित @ ऊपर और प्रश्न में मेरी गरीब उदाहरण के विपरीत TylerRinker का जवाब)

p <- 99 # how many columns? 
dat <- data.frame(matrix(rnorm(4*p), ncol = p)) 

समूह बनाने के लिए इस डेटा फ्रेम में कॉलम का नाम बदलें n लगातार कॉलम, ताकि यदि मुझे तीन कॉलम के समूहों में दिलचस्पी है तो मुझे कॉलम नाम 1,1,1,2,2,2,3,3,3, आदि मिलेगा या यदि मैं चार कॉलम के समूह चाहता था यह 1,1,1,1,2,2,2,2,3,3,3,3 होगा, आदि। मैं अभी तीनों के साथ जा रहा हूं (मुझे लगता है कि यह मेरे जैसे लोगों के लिए इंडेक्सिंग का एक प्रकार है अनुक्रमण के बारे में ज्यादा पता नहीं है जो)

n <- 3 # how many consecutive columns in the groups of interest? 
names(dat) <- rep(seq(1:(ncol(dat)/n)), each = n, len = (ncol(dat))) 

अब लागू का उपयोग करें और पंक्ति पाने के लिए tapply समूहों में से प्रत्येक के लिए इसका मतलब

dat.avs <- data.frame(t(apply(dat, 1, tapply, names(dat), mean))) 

मुख्य कमियां वे मूल डेटा स्तंभ नाम हैं प्रतिस्थापित किया गया है (हालांकि इसे समूह में संख्याओं को एक ne में डालकर दूर किया जा सकता है कॉलनाम के बजाए डब्ल्यू पंक्ति) और कॉलम नाम लागू-टैप्ली फ़ंक्शन द्वारा एक अनुपयोगी क्रम में वापस कर दिए जाते हैं।

p <- 99 # how many columns? 
dat <- data.frame(matrix(rnorm(4*p), ncol = p)) 
dat.t <- data.frame(t(dat)) 

n <- 3 # how many consecutive columns in the groups of interest? 
dat.t$groups <- as.character(rep(seq(1:(ncol(dat)/n)), each = n, len = (ncol(dat)))) 

library(data.table) 
DT <- data.table(dat.t) 
setkey(DT, groups) 
dat.av <- DT[, lapply(.SD,mean), by=groups] 

अपने त्वरित और रोगी के प्रयासों के लिए हर किसी को धन्यवाद:

@ Joran के सुझाव को

इसके अलावा, यहाँ एक data.table समाधान है!

+2

बस एक पॉइंटर जोड़ने के लिए जो 'लापरवाही (एसएसडी, माध्य)' मुहावरे चाहिए v1.8.1 में बहुत तेजी से प्राप्त करें धन्यवाद: i) [इस प्रश्न] में एक खोज (http://stackoverflow.com/questions/10584993/r-loop-over-columns-in-data-table) और ii) स्वचालित आंतरिक() 'माध्य()' का विकृति (विकी बिंदु 3 अब आवश्यक नहीं है)। इसके अलावा, '.SDcols' अक्सर उपयोगी होता है लेकिन इसकी आवश्यकता नहीं होती है। –

+0

@MatthewDowle आपके नोट के लिए धन्यवाद! 'एसडकोल्स' के बारे में जानना अच्छा है, जिसे मैं परिचित नहीं था, और 'data.table' सुनने के लिए बहुत अच्छा है, बस तेज़ी से बढ़ रहा है! – Ben

6

@david: averaging every 16 columns in r (अब बंद) द्वारा एक समान प्रश्न पूछा गया था, जिसे मैंने @ टायरर रिंकर के उत्तर को अपनाने के द्वारा उत्तर दिया, @joran और @Ben द्वारा दिए गए सुझाव के बाद। चूंकि परिणामी कार्य ओपी या भविष्य के पाठकों के लिए मदद की जा सकती है, इसलिए मैं ओपी के डेटा के उदाहरण के साथ उस समारोह को कॉपी कर रहा हूं।

# Function to apply 'fun' to object 'x' over every 'by' columns 
# Alternatively, 'by' may be a vector of groups 
byapply <- function(x, by, fun, ...) 
{ 
    # Create index list 
    if (length(by) == 1) 
    { 
     nc <- ncol(x) 
     split.index <- rep(1:ceiling(nc/by), each = by, length.out = nc) 
    } else # 'by' is a vector of groups 
    { 
     nc <- length(by) 
     split.index <- by 
    } 
    index.list <- split(seq(from = 1, to = nc), split.index) 

    # Pass index list to fun using sapply() and return object 
    sapply(index.list, function(i) 
      { 
       do.call(fun, list(x[, i], ...)) 
      }) 
} 

फिर, प्रतिकृति की मतलब खोजने के लिए:

byapply(dat, 3, rowMeans) 

या, प्रतिकृति की शायद मानक विचलन:

byapply(dat, 3, apply, 1, sd) 

अद्यतन

by कर सकते हैं जीआर के वेक्टर के रूप में भी निर्दिष्ट किया जाना चाहिए oups:

byapply(dat, c(1,1,1,2,2,2), rowMeans) 
+0

+1 धन्यवाद, यह भी सहायक है। – Ben

0

एक खूबसूरती से सरल समाधान करता है, तो आप क्या साहचर्य के रूप में जाना में, स्तंभों में से प्रत्येक के अद्वितीय संयोजन के लिए एक समारोह को लागू करने में रुचि रखते हैं नहीं है।

combinations <- combn(colnames(df),2,function(x) rowMeans(df[x])) 

तीन कॉलम, आदि के हर अद्वितीय संयोजन के लिए आंकड़ों की गणना करने के लिए, सिर्फ 2 एक 3. आपरेशन तेजी से इस तरह के apply परिवार के ऊपर का इस्तेमाल किया कार्यों के रूप में छोरों, से करने के लिए vectorized है और इस तरह बदल जाते हैं। यदि स्तंभों का क्रम मायने रखता है, तो आपको क्रमशः क्रमबद्ध सेटों को पुन: उत्पन्न करने के लिए डिज़ाइन किए गए क्रमपरिवर्तन एल्गोरिदम की आवश्यकता होती है: combinat::permn

+0

"यदि आदेश मायने रखता है" और इसका मतलब क्या है तो संयोजन :: permn फ़ंक्शन क्या है? क्या आप कोड को संपादित कर सकते हैं? – user3495945

+0

संयोजन क्रमपरिवर्तन के समान नहीं हैं: https://www.youtube.com/watch?v=s2W6Bce_T30 यदि इनपुट के मामले महत्वपूर्ण हैं, तो यह आपके द्वारा प्राप्त क्रमपरिवर्तन है। इस मामले में, 'ऑर्डर' कॉलम के क्रम के संदर्भ में है। –

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