2010-12-22 14 views
42

अक्सर मैं एक सूची को रूपांतरित करना चाहता हूं जिसमें प्रत्येक इंडेक्स में डेटा फ्रेम के समान तत्व प्रकार होते हैं। उदाहरण के लिए, मैं एक सूची है हो सकता है:डेटा फ्रेम के रूप में सूची डालने का सबसे प्रभावी तरीका क्या है?

> my.list 
[[1]] 
[[1]]$global_stdev_ppb 
[1] 24267673 

[[1]]$range 
[1] 0.03114799 

[[1]]$tok 
[1] "hello" 

[[1]]$global_freq_ppb 
[1] 211592.6 


[[2]] 
[[2]]$global_stdev_ppb 
[1] 11561448 

[[2]]$range 
[1] 0.08870838 

[[2]]$tok 
[1] "world" 

[[2]]$global_freq_ppb 
[1] 1002043 

मैं एक डेटा फ्रेम जहां प्रत्येक सूचकांक तत्व एक स्तंभ है के लिए इस सूची में परिवर्तित करना चाहते। जाने के लिए प्राकृतिक (मेरे लिए) बात करने के लिए उपयोग है do.call है: पर्याप्त

> my.matrix<-do.call("rbind", my.list) 
> my.matrix 
    global_stdev_ppb range  tok  global_freq_ppb 
[1,] 24267673   0.03114799 "hello" 211592.6  
[2,] 11561448   0.08870838 "world" 1002043 

सरल, लेकिन जब मैं एक डेटा फ्रेम के रूप में इस मैट्रिक्स कास्ट करने के लिए प्रयास करते हैं, कॉलम, सूची तत्व रहते हैं बल्कि वैक्टर से:

> my.df<-as.data.frame(my.matrix, stringsAsFactors=FALSE) 
> my.df[,1] 
[[1]] 
[1] 24267673 

[[2]] 
[1] 11561448 

वर्तमान में, डेटा फ्रेम डाली ठीक से प्राप्त करने के लिए मैं unlist और as.vector का उपयोग कर प्रत्येक स्तंभ पर पुनरावृत्ति कर रहा हूँ, तो इस तरह के रूप डेटा फ्रेम recasting:

new.list<-lapply(1:ncol(my.matrix), function(x) as.vector(unlist(my.matrix[,x]))) 
my.df<-as.data.frame(do.call(cbind, new.list), stringsAsFactors=FALSE) 

हालांकि, यह बहुत अक्षम लगता है। क्या ऐसा करने का बेहतर तरीका है?

+1

देखने '? Data.table :: rbindlist' – marbel

+0

2017 के रूप में आप का उपयोग करना चाहिए' your_list%>% कम (bind_rows) '' purrr' – Zafar

उत्तर

47

मुझे लगता है कि आप चाहते हैं:

> do.call(rbind, lapply(my.list, data.frame, stringsAsFactors=FALSE)) 
    global_stdev_ppb  range tok global_freq_ppb 
1   24267673 0.03114799 hello  211592.6 
2   11561448 0.08870838 world  1002043.0 
> str(do.call(rbind, lapply(my.list, data.frame, stringsAsFactors=FALSE))) 
'data.frame': 2 obs. of 4 variables: 
$ global_stdev_ppb: num 24267673 11561448 
$ range   : num 0.0311 0.0887 
$ tok    : chr "hello" "world" 
$ global_freq_ppb : num 211593 1002043 
+10

से 'plyr :: rbind.fill' अक्सर एक छोटे से है 'rbind.fill' से तेज़, और पूरा ऑपरेशन' plyr :: ldply (my.list, data.frame) ' – hadley

17

मैं आपको नहीं बता सकता है "के लिए सबसे कारगर" स्मृति या गति के मामले में है, लेकिन यह कोडिंग के मामले में बहुत कुशल है:

my.df <- do.call("rbind", lapply(my.list, data.frame)) 

lapply() data.frame() के साथ कदम एक ही पंक्ति डेटा फ्रेम जो तब rbind() के साथ अच्छा काम करता है में प्रत्येक सूची आइटम बदल जाता है

31

एक अन्य विकल्प है:

data.frame(t(sapply(mylist, `[`))) 

लेकिन इस सरल हेरफेर परिणाम सूचियों के एक डेटा फ्रेम में:

> str(data.frame(t(sapply(mylist, `[`)))) 
'data.frame': 2 obs. of 3 variables: 
$ a:List of 2 
    ..$ : num 1 
    ..$ : num 2 
$ b:List of 2 
    ..$ : num 2 
    ..$ : num 3 
$ c:List of 2 
    ..$ : chr "a" 
    ..$ : chr "b" 

उसी तर्ज पर इस के लिए एक विकल्प है, लेकिन अन्य समाधान के रूप में अब परिणाम एक ही है:

data.frame(lapply(data.frame(t(sapply(mylist, `[`))), unlist)) 

[संपादित करें: में @ मार्टिन मॉर्गन के दो समाधानों के समय शामिल हैं, जिनके पास दूसरे समाधान पर किनारे हैं जो वैक्टरों के डेटा फ्रेम को वापस करते हैं।] कुछ प्रतिनिधि समय साधारण सी समस्या:

mylist <- list(list(a = 1, b = 2, c = "a"), list(a = 2, b = 3, c = "b")) 

> ## @Joshua Ulrich's solution: 
> system.time(replicate(1000, do.call(rbind, lapply(mylist, data.frame, 
+          stringsAsFactors=FALSE)))) 
    user system elapsed 
    1.740 0.001 1.750 

> ## @JD Long's solution: 
> system.time(replicate(1000, do.call(rbind, lapply(mylist, data.frame)))) 
    user system elapsed 
    2.308 0.002 2.339 

> ## my sapply solution No.1: 
> system.time(replicate(1000, data.frame(t(sapply(mylist, `[`))))) 
    user system elapsed 
    0.296 0.000 0.301 

> ## my sapply solution No.2: 
> system.time(replicate(1000, data.frame(lapply(data.frame(t(sapply(mylist, `[`))), 
+            unlist)))) 
    user system elapsed 
    1.067 0.001 1.091 

> ## @Martin Morgan's Map() sapply() solution: 
> f = function(x) function(i) sapply(x, `[[`, i) 
> system.time(replicate(1000, as.data.frame(Map(f(mylist), names(mylist[[1]]))))) 
    user system elapsed 
    0.775 0.000 0.778 

> ## @Martin Morgan's Map() lapply() unlist() solution: 
> f = function(x) function(i) unlist(lapply(x, `[[`, i), use.names=FALSE) 
> system.time(replicate(1000, as.data.frame(Map(f(mylist), names(mylist[[1]]))))) 
    user system elapsed 
    0.653 0.000 0.658 
+0

एचआरएम के बराबर है .. इस उत्तर में 'प्रतिकृति()' उपयोग थोड़ा अजीब है। आप परीक्षण कर रहे हैं कि एक छोटी सूची को कई बार डेटा फ्रेम में परिवर्तित करना कितना कुशल है। ऐसा लगता है कि यह शायद ही कभी उपयोगी होगा। सूचियों की * बड़ी * सूची के रूपांतरण की दक्षता का परीक्षण करने के लिए और अधिक समझदारी नहीं होगी? – naught101

+0

@ naught101 संभवतः; आपके पास कोड है, इसे आज़माएं ;-) (वापस निष्कर्षों की रिपोर्ट करें --- यदि आप चाहें तो उन्हें अपने उत्तर में संपादित कर सकते हैं) –

+0

@ naught101 मेरे पास एक [साधन] है (http://stackoverflow.com/questions/26534438/इंट्राडाटाफ्रेम-विश्लेषण-निर्माण-एक-व्युत्पन्न-डेटा-फ्रेम-एक-डेटा-फ़्रेम/26535386) ऐसी एक सूची बनाने के लिए किसी को संख्याओं को क्रंच करने के लिए एक बड़ा डेटा फ्रेम है। 'Map' के चित्रण के लिए – jxramos

13

यह

f = function(x) function(i) sapply(x, `[[`, i) 

एक समारोह में एक समारोह है कि एक्स के i'th तत्व निकालता देता है। तो

Map(f(mylist), names(mylist[[1]])) 

नाम प्राप्त हुआ (धन्यवाद मानचित्र!) वैक्टर की सूची है कि एक डेटा फ्रेम

as.data.frame(Map(f(mylist), names(mylist[[1]]))) 

में बनाया जा सकता है गति के लिए इसका इस्तेमाल करने के unlist(lapply(...), use.names=FALSE)

रूप
f = function(x) function(i) unlist(lapply(x, `[[`, i), use.names=FALSE) 

एक अधिक सामान्य संस्करण

f = function(X, FUN) function(...) sapply(X, FUN, ...) 

है जब ऐसा आमतौर पर तेज है सूची-सूची सूचियां आती हैं? हो सकता है कि एक ऐसा पहला कदम हो जहां एक पुनरावृत्ति को और अधिक वेक्टरकृत द्वारा प्रतिस्थापित किया जा सके?

+2

+1। मुझे 'मानचित्र', 'घटाएं' एट शामिल करने की आवश्यकता है। अल मेरे हर दिन दिनचर्या में ... –

+0

इन चीजों का उपयोग कैसे करता है? 'As.data.frame (मानचित्र (एफ (mylist), नाम (mylist))) 'संस्करण मेरे लिए डेटा @DrewConway के प्रकार के लिए काम नहीं करता है और मैंने सूचियों के नामों के रूप में उपयोग किया है; मैं इसे 0 कॉलम और 0 पंक्तियों के साथ 'डेटा फ्रेम' के बदले में वापस लाता हूं। यहां तक ​​कि नामों के साथ, मैं इसे अपने उत्तर में 'mylist' के लिए काम करने के लिए नहीं मिल सकता। मैं वास्तव में उत्सुक हूं क्योंकि मैंने 'मैप' एट अल का उपयोग नहीं किया है, इसलिए मुझे यह जानने में दिलचस्पी है कि वे कैसे काम करते हैं, वे क्या करते हैं, जब तैनाती करने के लिए सबसे अच्छा आदि –

+0

ओह, नाम होना चाहिए (मेरी सूची [[1] ]), यानी, पहले तत्व से उप-तत्वों के नाम प्राप्त करें। –

14

हालांकि इस सवाल का लंबे समय से उत्तर दिया गया है, यह data.table पैकेज उनका कहना है लायक है rbindlist जो इस कार्य को पूरा करता बहुत जल्दी है:

library(microbenchmark) 
library(data.table) 
l <- replicate(1E4, list(a=runif(1), b=runif(1), c=runif(1)), simplify=FALSE) 

microbenchmark(times=5, 
    R=as.data.frame(Map(f(l), names(l[[1]]))), 
    dt=data.frame(rbindlist(l)) 
) 

मुझे

Unit: milliseconds 
expr  min  lq median  uq  max neval 
    R 31.060119 31.403943 32.278537 32.370004 33.932700  5 
    dt 2.271059 2.273157 2.600976 2.635001 2.729421  5 
2

देता dplyr पैकेज की bind_rows कुशल है।

one <- mtcars[1:4, ] 
two <- mtcars[11:14, ] 
system.time(dplyr::bind_rows(one, two)) 
    user system elapsed 
    0.001 0.000 0.001 
संबंधित मुद्दे

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