2015-06-25 13 views
7

में काम नहीं कर रहे हैं, मैं किसी फ़ंक्शन के भीतर डेटाटेबल का उपयोग करने का प्रयास कर रहा हूं, और मैं समझने की कोशिश कर रहा हूं कि मेरा कोड क्यों विफल रहा है।आर डेटाटेबल कॉलम नाम किसी फ़ंक्शन

DT <- data.table(my_name=c("A","B","C","D","E","F"),my_id=c(2,2,3,3,4,4)) 
> DT 
    my_name my_id 
1:  A  2 
2:  B  2 
3:  C  3 
4:  D  3 
5:  E  4 
6:  F  4 

मैं डीटी के लिए जो होगा "my_id" के विभिन्न मूल्यों के साथ "my_name", के सभी जोड़े बनाने के लिए कोशिश कर रहा हूँ:

Var1 Var2  
A C 
A D 
A E 
A F 
B C 
B D 
B E 
B F 
C E 
C F 
D E 
D F 

मेरे पास है मैं एक data.table इस प्रकार है "my_id" के मानों की एक दी गई जोड़ी के लिए "my_name" के सभी जोड़े को वापस करने के लिए एक फ़ंक्शन जो अपेक्षा के अनुसार काम करता है।

get_pairs <- function(id1,id2,tdt) { 
    return(expand.grid(tdt[my_id==id1,my_name],tdt[my_id==id2,my_name])) 
} 
> get_pairs(2,3,DT) 
Var1 Var2 
1 A C 
2 B C 
3 A D 
4 B D 

अब, मैं आईडी के सभी जोड़े, जो मैं आईडी के सभी जोड़े को खोजने और फिर get_pairs समारोह के साथ mapply का उपयोग करके करने की कोशिश के लिए इस समारोह निष्पादित करने के लिए चाहते हैं।

> combn(unique(DT$my_id),2) 
    [,1] [,2] [,3] 
[1,] 2 2 3 
[2,] 3 4 4 
tid1 <- combn(unique(DT$my_id),2)[1,] 
tid2 <- combn(unique(DT$my_id),2)[2,] 
mapply(get_pairs, tid1, tid2, DT) 
Error in expand.grid(tdt[my_id == id1, my_name], tdt[my_id == id2, my_name]) : 
    object 'my_id' not found 

फिर, अगर मैं एक mapply बिना एक ही बात करने की कोशिश, यह काम करता है।

get_pairs3(tid1[1],tid2[1],DT) 
Var1 Var2 
1 A C 
2 B C 
3 A D 
4 B D 

यह फ़ंक्शन केवल मैपली के भीतर उपयोग होने पर विफल क्यों होता है? मुझे लगता है कि डेटाटेबल नामों के दायरे से इसका कुछ संबंध है, लेकिन मुझे यकीन नहीं है।

वैकल्पिक रूप से, क्या इस कार्य को पूरा करने के लिए एक अलग/अधिक प्रभावी तरीका है? मेरे पास एक तीसरा आईडी "नमूना" के साथ एक बड़ा डेटा.table है और मुझे प्रत्येक नमूने के लिए इन सभी जोड़े को प्राप्त करने की आवश्यकता है (उदा। डीटी [नमूना == "sample_id",] पर ऑपरेटिंग)। मैं डेटाटेबल पैकेज में नया हूं, और मैं इसे सबसे कुशल तरीके से उपयोग नहीं कर रहा हूं।

+0

क्षमा करें, मैं क्यों mapply काम नहीं कर रहा है और इसलिए मेरा उत्तर में यह जिक्र नहीं किया था के बारे में यकीन नहीं है। 'Mapply' के लिए – Frank

+0

, यह काम करता है अगर आप सीधे' डीटी 'को फ़ंक्शन में डालते हैं और पैरामीटर के रूप में नहीं (हालांकि यह "यह क्यों काम नहीं कर रहा है" भाग को हल नहीं करता है ...) – Cath

+0

क्या प्रत्येक आईडी आईडी में हमेशा होता है बिल्कुल दो 'नाम'? – Frank

उत्तर

3

यह फ़ंक्शन केवल तभी विफल होता है जब मैपली के भीतर उपयोग किया जाता है? मुझे लगता है कि इसमें डेटाटेबल नामों के दायरे से कुछ करना है, लेकिन मैं सुनिश्चित नहीं हूं।

फ़ंक्शन विफल होने का कारण इस मामले में स्कॉइंग के साथ कुछ भी नहीं करना है। mapply फ़ंक्शन को वेक्टरिज़ करता है, यह प्रत्येक पैरामीटर के प्रत्येक तत्व को लेता है और फ़ंक्शन पर जाता है।तो, आपके मामले में, data.table तत्व इसके कॉलम हैं, इसलिए mapply पूर्ण data.table के बजाय कॉलम my_name को गुजर रहा है।

यदि आप पूरा data.table से mapply पास करना चाहते हैं, तो आपको MoreArgs पैरामीटर का उपयोग करना चाहिए। फिर आपका फ़ंक्शन काम करेगा:

res <- mapply(get_pairs, tid1, tid2, MoreArgs = list(tdt=DT), SIMPLIFY = FALSE) 
do.call("rbind", res) 
    Var1 Var2 
1  A C 
2  B C 
3  A D 
4  B D 
5  A E 
6  B E 
7  A F 
8  B F 
9  C E 
10 D E 
11 C F 
12 D F 
+0

आह ठीक है, यह समझ में आता है। क्या ऐसा इसलिए है क्योंकि एक डेटा.table भी एक सूची है()? – Sam

+0

@ सैम याप, 'डेटाटेबल', 'data.frame', 'tbl_df की कुछ अतिरिक्त गुणों के साथ सूचियां हैं। –

4

की गणना के लिए सभी संभव जोड़े

u_name <- unique(DT$my_name) 
all_pairs <- CJ(u_name,u_name)[V1 < V2] 

की गणना जोड़े मनाया

obs_pairs <- unique(
    DT[,{un <- unique(my_name); CJ(un,un)[V1 < V2]}, by=my_id][, !"my_id", with=FALSE] 
) 

अंतर लो

all_pairs[!J(obs_pairs)] 

CJ को छोड़कर यह सब के साथ एक data.table बनाता है कि expand.grid की तरह है इसके कॉलम इसकी कुंजी के रूप में। एक डेटा.table X को X[J(Y)] में शामिल होने के लिए या X[!J(Y)] (अंतिम पंक्ति की तरह) में शामिल होने के लिए कुंजी होना चाहिए। J वैकल्पिक है, लेकिन यह और अधिक स्पष्ट करता है कि हम एक साथ जुड़ रहे हैं।


सरलीकरण। @ कैथजी ने इंगित किया कि obs_pairs का निर्माण करने का एक क्लीनर तरीका है यदि आपके पास हमेशा "आईडी" (उदाहरण डेटा में) के लिए दो क्रमबद्ध "नाम" होते हैं: CJ(un,un)[V1 < V2] के स्थान पर as.list(un) का उपयोग करें।

+0

क्षमा करें, मैंने उल्लेख नहीं किया कि "my_name" में डुप्लीकेट हो सकते हैं लेकिन यदि कोई डुप्लीकेट नहीं है तो आपका समाधान काम करता है। यद्यपि यह मेरे दृष्टिकोण से कहीं अधिक सुरुचिपूर्ण है। स्पष्ट रूप से मुझे जुड़ने के लिए और अधिक सीखने की जरूरत है। – Sam

+0

@ सैम मैंने अभी उस मामले के लिए संपादित किया है (अगर मैं इसे सही ढंग से समझता हूं)। – Frank

3

फ़ंक्शन debugonce() इन परिदृश्यों में बेहद उपयोगी है।

debugonce(mapply) 
mapply(get_pairs, tid1, tid2, DT) 

# Hit enter twice 
# from within BROWSER 
debugonce(FUN) 
# Hit enter twice 
# you'll be inside your function, and then type DT 
DT 
# [1] "A" "B" "C" "D" "E" "F" 
Q # (to quit debugging mode) 

जो गलत है। असल में, mapply() प्रत्येक इनपुट तर्क का पहला तत्व लेता है और इसे आपके कार्य में भेज देता है। इस मामले में आपने डेटा.table प्रदान किया है, जो सूची भी है। तो, पूरे डेटा.table को पारित करने के बजाय, यह सूची के प्रत्येक तत्व (कॉलम) को पार कर रहा है।

तो, आप कार्य करके यह आसपास पहुंच सकते हैं:

mapply(get_pairs, tid1, tid2, list(DT)) 

लेकिन mapply() डिफ़ॉल्ट रूप से परिणाम को सरल है, और इसलिए आप एक matrix वापस मिल चाहते हैं। आपको SIMPLIFY = FALSE का उपयोग करना होगा।

mapply(get_pairs, tid1, tid2, list(DT), SIMPLIFY = FALSE) 

या बस Map का उपयोग करें:

Map(get_pairs, tid1, tid2, list(DT)) 

उपयोग rbindlist() परिणाम बाध्य करने के लिए।

HTH

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