2012-07-03 11 views
65

मेरे पास एक ऐसा फ़ंक्शन है जो एक सूची में दो मान देता है। दोनों मानों को दो नए कॉलम में डेटाटेबल में जोड़ा जाना चाहिए। समारोह का मूल्यांकन महंगा है, इसलिए मैं फ़ंक्शन को दो बार गणना करने से बचना चाहता हूं। यहां उदाहरण दिया गया है:एक फ़ंक्शन कॉल में R data.table में एकाधिक कॉलम जोड़ें?

library(data.table) 
example(data.table) 
DT 
    x y v 
1: a 1 42 
2: a 3 42 
3: a 6 42 
4: b 1 4 
5: b 3 5 
6: b 6 6 
7: c 1 7 
8: c 3 8 
9: c 6 9 

यहां मेरे फ़ंक्शन का एक उदाहरण दिया गया है। याद रखें कि मैंने कहा यह महंगा गणना, उसके ऊपर वहाँ अन्य दिए गए मान से एक वापसी मान निकालना (नीचे उदाहरण के रूप में) कोई रास्ता नहीं है है:

myfun <- function (y, v) 
{ 
ret1 = y + v 
ret2 = y - v 
return(list(r1 = ret1, r2 = ret2)) 
} 

यहाँ एक बयान में दो कॉलम जोड़ने के लिए मेरा तरीका है । उस व्यक्ति को दो बार माईफन कॉल करने की आवश्यकता है, हालांकि:

DT[,new1:=myfun(y,v)$r1][,new2:=myfun(y,v)$r2] 

    x y v new1 new2 
1: a 1 42 43 -41 
2: a 3 42 45 -39 
3: a 6 42 48 -36 
4: b 1 4 5 -3 
5: b 3 5 8 -2 
6: b 6 6 12 0 
7: c 1 7 8 -6 
8: c 3 8 11 -5 
9: c 6 9 15 -3 

यह कैसे करें इस पर कोई सुझाव? जब भी मैं myfun को कॉल करता हूं, तो मैं r2 को एक अलग वातावरण में सहेज सकता हूं, मुझे एक समय में संदर्भ द्वारा दो कॉलम जोड़ने का एक तरीका चाहिए।

+0

आपका फ़ंक्शन डेटा फ्रेम में क्यों नहीं लेता है और सीधे डेटा फ्रेम लौटाता है? 'पीछे <- समारोह (y, v) { ret1 = y + v ret2 = y - वी वापसी (सूची (आर 1 = ret1, r2 = ret2)) } –

+3

@Etienne क्योंकि कि बनाने के लिए प्रतियां आदानों एक नया आउटपुट फ्लोरियन बड़े डेटासेट के साथ अपनी मेमोरी दक्षता के लिए 'data.table' का उपयोग कर रहा है; यह 'x', 'y' या' v' को बिल्कुल भी कॉपी नहीं करता है, यहां तक ​​कि एक बार भी। राम में 20 जीबी डेटासेट सोचें। –

उत्तर

86

आप अपने समारोह कॉल के उत्पादन में संग्रहीत कर सकती है:

z <- myfun(DT$y,DT$v) 
head(DT[,new1:=z$r1][,new2:=z$r2]) 
#  x y v new1 new2 
# [1,] a 1 42 43 -41 
# [2,] a 3 42 45 -39 
# [3,] a 6 42 48 -36 
# [4,] b 1 4 5 -3 
# [5,] b 3 5 8 -2 
# [6,] b 6 6 12 0 

लेकिन यह भी काम करने के लिए लगता है:

DT[, c("new1","new2") := myfun(y,v), with = FALSE] 

न्यू data.table v1.8.3 में पर आर-फोर्ज, सुविधा के लिए with = FALSE अब और आवश्यकता नहीं है:

DT[, c("new1","new2") := myfun(y,v)] 

मिनट तक लाइव समाचार here है।

+2

वाह, वह दूसरा अद्भुत है, धन्यवाद! बस इसे 'डीबग (myfun)' के साथ चलाया गया यह देखने के लिए कि इसे कितनी बार कहा जाता है: यह एक बार है। महान। –

+1

+10 भी मुझसे। मैंने अभी [एफआर # 2120] उठाया है (https://r-forge.r-project.org/tracker/index.php?func=detail&aid=2120&group_id=240&atid=978) "आवश्यकता को रोकना 'के साथ = FALSE' ': =' " –

+6

के एलएचएस के लिए ध्यान दें कि सूची रीसाइक्लिंग भी किया जाता है; उदाहरण के लिए, 'सी (" ए "," बी "," सी "," डी "): = सूची (1,2)' 1 को 'ए' और 'सी' में डालती है, और 2 'बी' और' d में '। यदि कोई भी स्तंभ मौजूद नहीं है तो उन्हें संदर्भ द्वारा जोड़ा जाएगा। सुनिश्चित नहीं है कि कितना उपयोगी ': = 'रीसाइक्लिंग अभ्यास में है। यह 'सी ("ए", "बी", "सी") के लिए अधिक है: = NULL' जो उन 3 कॉलम को हटा देता है। आंतरिक रूप से यह एक (अर्थात्) सूची लंबाई के लिए NULL का एक रीसायकल है। –

-5

आपका फ़ंक्शन डेटा फ्रेम में क्यों नहीं लेता है और सीधे डेटा फ्रेम लौटाता है?

myfun <- function (DT) 
{ 
DT$ret1 = with(DT, y + v) 
DT$ret2 = with(DT, y - v) 
return(DT) 
} 
+25

ऊपर उठा सकते हैं क्योंकि यह दो बार 'डीटी' की प्रतिलिपि बनाता है। फ्लोरियन बड़े डेटासेट के साथ अपनी मेमोरी दक्षता के लिए 'data.table' का उपयोग कर रहा है; यह 'x', 'y' या' v' को बिल्कुल भी कॉपी नहीं करता है, यहां तक ​​कि एक बार भी। –

2

पिछले जवाब पर निर्माण करने के लिए, एक एक समारोह है कि उत्पादन से अधिक स्तंभ के साथ lapply उपयोग कर सकते हैं। डेटाटेबल के अधिक कॉलम के साथ फ़ंक्शन का उपयोग करना संभव है।

myfun <- function(a,b){ 
    res1 <- a+b 
    res2 <- a-b 
    list(res1,res2) 
} 

DT <- data.table(z=1:10,x=seq(3,30,3),t=seq(4,40,4)) 
DT 

## DT 
##  z x t 
## 1: 1 3 4 
## 2: 2 6 8 
## 3: 3 9 12 
## 4: 4 12 16 
## 5: 5 15 20 
## 6: 6 18 24 
## 7: 7 21 28 
## 8: 8 24 32 
## 9: 9 27 36 
## 10: 10 30 40 

col <- colnames(DT) 
DT[, paste0(c('r1','r2'),rep(col,each=2)):=unlist(lapply(.SD,myfun,z), 
                recursive=FALSE),.SDcols=col] 
## > DT 
##  z x t r1z r2z r1x r2x r1t r2t 
## 1: 1 3 4 2 0 4 2 5 3 
## 2: 2 6 8 4 0 8 4 10 6 
## 3: 3 9 12 6 0 12 6 15 9 
## 4: 4 12 16 8 0 16 8 20 12 
## 5: 5 15 20 10 0 20 10 25 15 
## 6: 6 18 24 12 0 24 12 30 18 
## 7: 7 21 28 14 0 28 14 35 21 
## 8: 8 24 32 16 0 32 16 40 24 
## 9: 9 27 36 18 0 36 18 45 27 
## 10: 10 30 40 20 0 40 20 50 30 
1

उत्तर का उपयोग नहीं किया जा सकता है जैसे कि फ़ंक्शन वेक्टरकृत नहीं होता है।

निम्नलिखित स्थिति में उदाहरण के लिए यह रूप में इरादा काम नहीं करेगा:

myfun <- function (y, v, g) 
{ 
    ret1 = y + v + length(g) 
    ret2 = y - v + length(g) 
    return(list(r1 = ret1, r2 = ret2)) 
} 
DT 
# v y     g 
# 1: 1 1     1 
# 2: 1 3    4,2 
# 3: 1 6    9,8,6 

DT[,c("new1","new2"):=myfun(y,v,g)] 
DT 
# v y  g new1 new2 
# 1: 1 1  1 5 3 
# 2: 1 3 4,2 7 5 
# 3: 1 6 9,8,6 10 8 

यह हमेशा स्तंभ g के आकार जोड़ देगा, नहीं g

ऐसे में एक समाधान में प्रत्येक वेक्टर के आकार मामला है:

DT[, c("new1","new2") := data.table(t(mapply(myfun,y,v,g)))] 
DT 
# v y  g new1 new2 
# 1: 1 1  1 3 1 
# 2: 1 3 4,2 6 4 
# 3: 1 6 9,8,6 10 8 
संबंधित मुद्दे