मेरे पास एक सूची है जिसमें अलग-अलग वर्षों को कवर करने वाली बड़ी संख्या में समय श्रृंखला डेटाफ्रेम शामिल हैं। मैं सूची को सफलतापूर्वक अनपैक करने के लिए lapply का उपयोग कर रहा हूं लेकिन मुझे कुछ जल्दी चाहिए। एक जटिलता यह है कि कुछ डेटाफ्रेम खाली हैं लेकिन मैं उनका रिकॉर्ड रखना चाहता हूं ताकि अनपैकिंग के बाद मैं डेटा के साथ सही लेबल cbind कर सकूं।

मैं माइक्रोबेंचमार्क का उपयोग करके उदाहरण डेटा के साथ अपने वर्तमान प्रयास का समय दे रहा हूं।

library("plyr")
library("microbenchmark")

# Create some example dataframes of varying length.
ts1 <- data.frame(year=2004:2019, value=14:29)
ts2 <- data.frame(year=2006:2018, value=18:6)
ts3 <- NULL
ts4 <- data.frame(year=2005:2017, value=25:37)
ts5 <- NULL

# Combine the example dataframes into a list.
ts_data <- list(ts1, ts2, ts3, ts4, ts5)

# Function to unpack time series data if not empty and return a dataframe.
fn_unpack_ts <- function(ts) {
  if (!plyr::empty(ts)) {  
    df <- t(ts$value)
    colnames(df) <- ts$year
  } else {
    df <- NA
  }
  return(as.data.frame(df))
}

# Use lapply to run through each dataframe.
microbenchmark::microbenchmark(
l_ts <- Reduce(plyr::rbind.fill, lapply(ts_data, fn_unpack_ts)), times=100
)

# Tidy up the final dataframe.
l_ts$df <- NULL

आवश्यक आउटपुट डेटाफ़्रेम इस तरह दिखता है:

> l_ts
   2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019
 1   14   15   16   17   18   19   20   21   22   23   24   25   26   27   28   29
 2   NA   NA   18   17   16   15   14   13   12   11   10    9    8    7    6   NA
 3   NA   NA   NA   NA   NA   NA   NA   NA   NA   NA   NA   NA   NA   NA   NA   NA
 4   NA   25   26   27   28   29   30   31   32   33   34   35   36   37   NA   NA
 5   NA   NA   NA   NA   NA   NA   NA   NA   NA   NA   NA   NA   NA   NA   NA   NA

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

           min       lq     mean   median       uq     max neval
l_ts  2.844698 3.024238 3.283312 3.093525 3.357831 9.21223   100

मैं जानना चाहता हूं कि मेरे उदाहरण डेटा को अनपॅक करने के लिए एक और अधिक कुशल दृष्टिकोण है या नहीं। मुझे संदेह है कि यह हर बार एक डेटाफ्रेम नहीं लौटाएगा, लेकिन यह एकमात्र तरीका है जिससे मैं इसे काम करने के लिए rbind.fill का उपयोग करते हुए अलग-अलग वर्षों की संख्या को संभालने के लिए प्राप्त कर सकता हूं।

अपडेट करें

#A द्वारा प्रस्तावित बहुत अच्छा समाधान। सुलेमान और #उवे। 1,098 पंक्तियों और 10 दोहराव वाले वास्तविक डेटा के साथ मेरे परीक्षण से पता चलता है:

expr                                                               mean (ms)     
Reduce(rbind.fill, lapply(ts_data, fn_unpack_ts))                  1326.2   
purrr::map_dfr(ts_data, fn_unpack_ts)                               133.7 
dcast(rbindlist(ts_data, idcol="id")[CJ(id=seq_along(ts_data),
  year, unique=TRUE), on=.(id, year)], id~year)                      15.0

... इसलिए मैं घोषणा करता हूं कि rbindlist विजेता के करीब पहुंचें।

0
Andrew Eaves 11 जून 2019, 08:23

2 जवाब

सबसे बढ़िया उत्तर

यहां एक वैकल्पिक दृष्टिकोण है जो डेटाफ़्रेम को संयोजित करने के लिए rbindlist() का उपयोग करता है, एक क्रॉस जॉइन CJ() लापता समय अनुक्रमों की आईडी को पूरा करने के लिए, और dcast() लंबे से विस्तृत प्रारूप को फिर से आकार देने के लिए:

library(data.table)
dcast(rbindlist(ts_data, idcol = "id")[CJ(id = seq_along(ts_data), year, unique = TRUE), on = .(id, year)], id ~ year)
   id 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019
1:  1   14   15   16   17   18   19   20   21   22   23   24   25   26   27   28   29
2:  2   NA   NA   18   17   16   15   14   13   12   11   10    9    8    7    6   NA
3:  3   NA   NA   NA   NA   NA   NA   NA   NA   NA   NA   NA   NA   NA   NA   NA   NA
4:  4   NA   25   26   27   28   29   30   31   32   33   34   35   36   37   NA   NA
5:  5   NA   NA   NA   NA   NA   NA   NA   NA   NA   NA   NA   NA   NA   NA   NA   NA

मेरे पास दिए गए बहुत छोटे नमूना डेटासेट के लिए बेंचमार्क समय शामिल नहीं है क्योंकि यह केवल फ़ंक्शन कॉल के ऊपरी हिस्से को मापेगा। एक सार्थक बेंचमार्क के लिए सभी समाधानों के लिए समय का अध्ययन एक कंप्यूटर पर अलग-अलग (छोटे और बड़े) आकार के आकार में करना होगा।

1
Uwe 11 जून 2019, 10:01

purrr::map_dfr का उपयोग करके यहां एक विकल्प दिया गया है

microbenchmark::microbenchmark(
  l_ts <- purrr::map_dfr(ts_data, fn_unpack_ts), unit = "ms",times=100
)

Unit: milliseconds
                                  expr      min        lq      mean    median       uq      max neval
l_ts <- map_dfr(ts_data, fn_unpack_ts) 0.367476 0.3829495 0.4368147 0.3925645 0.417654 1.181447   100
2
A. Suliman 11 जून 2019, 08:37