2012-05-22 12 views
15
गणना करने के लिए

के निम्न डेटा लेते हैं:आर: data.table का उपयोग कर: = संचालन नए कॉलम

    : प्रत्येक टिकर/अवधि संयोजन के लिए अब

    dt <- data.table(TICKER=c(rep("ABC",10),"DEF"), 
         PERIOD=c(rep(as.Date("2010-12-31"),10),as.Date("2011-12-31")), 
         DATE=as.Date(c("2010-01-05","2010-01-07","2010-01-08","2010-01-09","2010-01-10","2010-01-11","2010-01-13","2010-04-01","2010-04-02","2010-08-03","2011-02-05")), 
         ID=c(1,2,1,3,1,2,1,1,2,2,1),VALUE=c(1.5,1.3,1.4,1.6,1.4,1.2,1.5,1.7,1.8,1.7,2.3)) 
    setkey(dt,TICKER,PERIOD,ID,DATE) 
    

    , मैं एक नया कॉलम में निम्न की जरूरत है

  • PRIORAVG: वर्तमान आईडी को छोड़कर, प्रत्येक आईडी के नवीनतम VALUE का अर्थ, यह 180 दिन से अधिक पुराना नहीं है।
  • PREV: उसी आईडी से पिछले मूल्य।

परिणाम इस तरह दिखना चाहिए:

 TICKER  PERIOD  DATE ID VALUE PRIORAVG PREV 
[1,] ABC 2010-12-31 2010-01-05 1 1.5  NA NA 
[2,] ABC 2010-12-31 2010-01-08 1 1.4  1.30 1.5 
[3,] ABC 2010-12-31 2010-01-10 1 1.4  1.45 1.4 
[4,] ABC 2010-12-31 2010-01-13 1 1.5  1.40 1.4 
[5,] ABC 2010-12-31 2010-04-01 1 1.7  1.40 1.5 
[6,] ABC 2010-12-31 2010-01-07 2 1.3  1.50 NA 
[7,] ABC 2010-12-31 2010-01-11 2 1.2  1.50 1.3 
[8,] ABC 2010-12-31 2010-04-02 2 1.8  1.65 1.2 
[9,] ABC 2010-12-31 2010-08-03 2 1.7  1.70 1.8 
[10,] ABC 2010-12-31 2010-01-09 3 1.6  1.35 NA 
[11,] DEF 2011-12-31 2011-02-05 1 2.3  NA NA 

नोट पंक्ति 9 पर PRIORAVG 1.7 के बराबर (जो पंक्ति 5, जो अतीत में केवल पूर्व अवलोकन है पर VALUE के बराबर है 180 दिनों के बाद ID)

मैंने data.table पैकेज की खोज की है, लेकिन मुझे := फ़ंक्शन पूरी तरह से समझ में नहीं आता है। जब मैं इसे सरल रखता हूं, ऐसा लगता है कि यह काम करता है। प्रत्येक आईडी के लिए पिछले मान प्राप्त करने के लिए (मैं this question का हल पर इस आधार पर):

dt[,PREV:=dt[J(TICKER,PERIOD,ID,DATE-1),roll=TRUE,mult="last"][,VALUE]] 

यह अच्छा काम करता है, और यह केवल 0.13 सेकंड लेता है ~ 250k पंक्तियों के साथ मेरी डाटासेट से अधिक यह कार्रवाई करने के; मेरे वेक्टर स्कैन फ़ंक्शन को समान परिणाम मिलते हैं लेकिन लगभग 30,000 बार धीमे होते हैं।

ठीक है, इसलिए मुझे अपनी पहली आवश्यकता मिली है। चलो दूसरी, अधिक जटिल आवश्यकता के लिए मिलता है। अभी तक मेरे लिए अभी तक उपवास विधि कुछ वेक्टर स्कैन का उपयोग कर रही है और प्रत्येक पंक्ति के परिणाम प्राप्त करने के लिए plyr फ़ंक्शन adply के माध्यम से फ़ंक्शन फेंक रही है।

calc <- function(df,ticker,period,id,date) { 
    df <- df[df$TICKER == ticker & df$PERIOD == period 
     & df$ID != id & df$DATE < date & df$DATE > date-180, ] 
    df <- df[order(df$DATE),] 
    mean(df[!duplicated(df$ID, fromLast = TRUE),"VALUE"]) 
} 

df <- data.frame(dt) 
adply(df,1,function(x) calc(df,x$TICKER,x$PERIOD,x$ID,x$DATE)) 

मैं एक data.frame के लिए समारोह में लिखा था और यह एक data.table के साथ काम करने लगता है। 5000 पंक्तियों के उप-समूह के लिए इसमें लगभग 44 सेकंड लगते हैं लेकिन मेरे डेटा में> 1 मिलियन पंक्तियां होती हैं। मुझे आश्चर्य है कि इसे := के उपयोग के माध्यम से अधिक कुशल बनाया जा सकता है।

dt[J("ABC"),last(VALUE),by=ID][,mean(V1)] 

यह एबीसी के लिए प्रत्येक आईडी के लिए नवीनतम VALUE का औसत चुनने के लिए काम करता है।

dt[,PRIORAVG:=dt[J(TICKER,PERIOD),last(VALUE),by=ID][,mean(V1)]] 

लेकिन यह अपेक्षा के अनुरूप काम नहीं करता है, के रूप में यह केवल वर्तमान टिकर/अवधि के लिए के बजाय सभी टिकर/अवधि के लिए सभी पिछले मानों का औसत लेता है। तो यह एक ही औसत मूल्य प्राप्त करने वाली सभी पंक्तियों के साथ समाप्त होता है। क्या मैं कुछ गलत कर रहा हूं या यह := की सीमा है?

+1

संकेत: पिछले 180 दिनों के साथ प्रचलित अवलोकन के लिए विरासत में शामिल होने के लिए ('i'' उपसर्ग: '[, जे = सूची (..., आयु = PERIOD-i.PERIOD, ...),] [आयु <180] ', और' पिछले = 'पिछले" '' '(' '' 'के बजाय, ' –

+1

प्रश्न में डेटा पैनल को उपरोक्त कोड निकालने के लिए अलग-अलग कुंजी के रूप में जाना जाता है। और इसमें एक' ' ऐसा लगता है। –

+0

जोड़ा गया डेटा जो 180 दिनों की आवश्यकता – Dirk

उत्तर

12

शानदार सवाल। इस प्रयास करें:

dt 
    TICKER  PERIOD  DATE ID VALUE 
[1,] ABC 2010-12-31 2010-01-05 1 1.5 
[2,] ABC 2010-12-31 2010-01-08 1 1.4 
[3,] ABC 2010-12-31 2010-01-10 1 1.4 
[4,] ABC 2010-12-31 2010-01-13 1 1.5 
[5,] ABC 2010-12-31 2010-01-07 2 1.3 
[6,] ABC 2010-12-31 2010-01-11 2 1.2 
[7,] ABC 2010-12-31 2010-01-09 3 1.6 
[8,] DEF 2011-12-31 2011-02-05 1 2.3 

ids = unique(dt$ID) 
dt[,PRIORAVG:=NA_real_] 
for (i in 1:nrow(dt)) 
    dt[i,PRIORAVG:=dt[J(TICKER[i],PERIOD[i],setdiff(ids,ID[i]),DATE[i]), 
         mean(VALUE,na.rm=TRUE),roll=TRUE,mult="last"]] 
dt 
    TICKER  PERIOD  DATE ID VALUE PRIORAVG 
[1,] ABC 2010-12-31 2010-01-05 1 1.5  NA 
[2,] ABC 2010-12-31 2010-01-08 1 1.4  1.30 
[3,] ABC 2010-12-31 2010-01-10 1 1.4  1.45 
[4,] ABC 2010-12-31 2010-01-13 1 1.5  1.40 
[5,] ABC 2010-12-31 2010-01-07 2 1.3  1.50 
[6,] ABC 2010-12-31 2010-01-11 2 1.2  1.50 
[7,] ABC 2010-12-31 2010-01-09 3 1.6  1.35 
[8,] DEF 2011-12-31 2011-02-05 1 2.3  NA 

तो क्या आप एक मामूली सरलीकरण के साथ पहले से ही था ...

dt[,PREV:=dt[J(TICKER,PERIOD,ID,DATE-1),VALUE,roll=TRUE,mult="last"]] 

    TICKER  PERIOD  DATE ID VALUE PRIORAVG PREV 
[1,] ABC 2010-12-31 2010-01-05 1 1.5  NA NA 
[2,] ABC 2010-12-31 2010-01-08 1 1.4  1.30 1.5 
[3,] ABC 2010-12-31 2010-01-10 1 1.4  1.45 1.4 
[4,] ABC 2010-12-31 2010-01-13 1 1.5  1.40 1.4 
[5,] ABC 2010-12-31 2010-01-07 2 1.3  1.50 NA 
[6,] ABC 2010-12-31 2010-01-11 2 1.2  1.50 1.3 
[7,] ABC 2010-12-31 2010-01-09 3 1.6  1.35 NA 
[8,] DEF 2011-12-31 2011-02-05 1 2.3  NA NA 

यदि यह एक प्रोटोटाइप के रूप में ठीक है तो एक बड़ी गति सुधार पाश रखने लेकिन := के बजाय set() उपयोग करते हैं, भूमि के ऊपर कम करने के लिए किया जाएगा:

for (i in 1:nrow(dt)) 
    set(dt,i,6L,dt[J(TICKER[i],PERIOD[i],setdiff(ids,ID[i]),DATE[i]), 
        mean(VALUE,na.rm=TRUE),roll=TRUE,mult="last"]) 
dt 
    TICKER  PERIOD  DATE ID VALUE PRIORAVG PREV 
[1,] ABC 2010-12-31 2010-01-05 1 1.5  NA NA 
[2,] ABC 2010-12-31 2010-01-08 1 1.4  1.30 1.5 
[3,] ABC 2010-12-31 2010-01-10 1 1.4  1.45 1.4 
[4,] ABC 2010-12-31 2010-01-13 1 1.5  1.40 1.4 
[5,] ABC 2010-12-31 2010-01-07 2 1.3  1.50 NA 
[6,] ABC 2010-12-31 2010-01-11 2 1.2  1.50 1.3 
[7,] ABC 2010-12-31 2010-01-09 3 1.6  1.35 NA 
[8,] DEF 2011-12-31 2011-02-05 1 2.3  NA NA 

कि एक बहुत तेजी से होना चाहिए प्रश्न में दिखाए गए बार-बार वेक्टर स्कैन।

या, ऑपरेशन वेक्टरकृत किया जा सकता है। लेकिन इस कार्य की विशेषताओं के कारण लिखना और पढ़ना आसान नहीं होगा।

बीटीडब्ल्यू, इस प्रश्न में कोई डेटा नहीं है जो 180 दिन की आवश्यकता का परीक्षण करेगा। यदि आप कुछ जोड़ते हैं और अपेक्षित आउटपुट फिर से दिखाते हैं तो मैं टिप्पणियों में उल्लिखित विरासत में शामिल होने के लिए उम्र की गणना जोड़ दूंगा।

+0

ग्रेट उत्तर के अपेक्षित परिणाम दिखाता है। वेक्टर विधि के लिए कई घंटे मेरे डेटासेट (180k पंक्तियों) बनाम के पहले भाग की गणना करने में केवल 20 मिनट लगते हैं। मुझे मौजूदा आईडी के अलावा सभी को चुनने के लिए setdiff() का उपयोग पसंद है, लेकिन मुझे लगता है कि यह बड़ी संख्या में आईडी के साथ चीजों को धीमा कर सकता है (मेरे डेटासेट में 6000 हैं और केवल टिकर प्रति औसत 16 आईडी हैं)। – Dirk

+0

अच्छा। 20 मिनट अभी भी इस काम के लिए बहुत लंबा लगता है। 'सेट() 'का उपयोग करना? वैसे भी, मंत्र जाता है, 'Rprof', 'Rprof',' Rprof'। हां 'setdiff() 'पर (यदि' Rprof' दिखाता है कि समय का कारण बन रहा है), तो आप इसे पहले से कर सकते हैं और प्रत्येक आईडी के लिए "अन्य" आईडी की एक सूची या वातावरण संग्रहीत कर सकते हैं और फिर इसे देखें। या एक आसान तरीका हो सकता है मैं याद कर रहा हूँ। –

+0

वास्तव में 'सेट() 'का उपयोग करने के साथ है। 'setdiff()' में अधिक समय नहीं लग रहा है, यह 'setdiff()' के आउटपुट का उपयोग करके सबसेटिंग है जो करता है। 5k पंक्तियों के उप-समूह के साथ परीक्षण, 738 से 5866 तक 'आईडी' बढ़ाना 60% गणना समय जोड़ता है। – Dirk

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