2012-04-09 7 views
21

के साथ चर के रूप में एकाधिक कॉलम का उपयोग करें मेरे पास dataframe है और मैं एक ऐसा फ़ंक्शन लागू करना चाहता हूं जो तीन कॉलम के मान लेता है और तीन मानों के बीच न्यूनतम अंतर की गणना करता है।सैपली

#dataset 
df <- data.frame(a= sample(1:100, 10),b = sample(1:100, 10),c= sample(1:100, 10)) 

#function 
minimum_distance <- function(a,b,c) 
{ 
    dist1 <- abs(a-b) 
    dist2 <- abs(a-c) 
    dist3 <- abs(b-c) 
    return(min(dist1,dist2,dist3)) 
} 

मैं की तरह कुछ के लिए देख रहा हूँ:

df$distance <- sapply(df, function(x) minimum_distance(x$a,x$b,x$c)) 
## errormessage 
Error in x$a : $ operator is invalid for atomic vectors 

मैं ddply उपयोग कर सकते हैं:

df2 <- ddply(df,.(a),function(r) {data.frame(min_distance=minimum_distance(r$a,r$b, r$c))}, .drop=FALSE) 

इस कॉलम के सभी नहीं रखता। कोई सुझाव?

संपादित करें:

df$distance <- mapply(minimum_distance, df$a, df$b, df$c) 

उत्तर

38

mapply() का प्रयास करें::

qq <- mapply(minimum_distance, df$a, df$b, df$c) 
+0

सरल और सुरुचिपूर्ण। धन्यवाद – zach

+0

कौन सा सबसे तेज़ है? या अधिक कुशल? – Bharath

6

इस प्रयास करें:

do.call("mapply", c(list(minimum_distance), df)) 

लेकिन आप vectorized संस्करण लिख सकते हैं:

मैं का उपयोग कर समाप्त हो गया
pminimum_distance <- function(a,b,c) 
{ 
dist1 <- abs(a-b) 
dist2 <- abs(a-c) 
dist3 <- abs(b-c) 
return(pmin(dist1,dist2,dist3)) 
} 
pminimum_distance(df$a, df$b, df$c) 

# or 
do.call("pminimum_distance", df) 
+0

यह स्मार्ट है लेकिन थोड़ा सा सरल सीधे धन्यवाद। – zach

4

मैं इस उत्तर दिया गया है पता है, लेकिन मैं वास्तव में एक अलग दृष्टिकोण है कि कॉलम के किसी भी संख्या लेता है और एक बाहरी दृष्टिकोण का उपयोग कर अधिक generalizable है काफ़ी होगा:

vdiff <- function(x){ 
    y <- outer(x, x, "-") 
    min(abs(y[lower.tri(y)])) 
} 

apply(df, 1, vdiff) 

मुझे लगता है कि यह एक छोटे से क्लीनर और लचीला है।

संपादित करें: प्रति ज़ैच की टिप्पणियां मैं इस औपचारिक फ़ंक्शन का प्रस्ताव करता हूं जो गैर-संख्यात्मक कॉलम के साथ डेटा फ्रेम पर काम करता है और साथ ही उन्हें हटाकर और संख्यात्मक कॉलम पर कार्य करता है।

cdif <- function(dataframe){ 
    df <- dataframe[, sapply(dataframe, is.numeric)] 
    vdiff <- function(x){ 
     y <- outer(x, x, "-") 
     min(abs(y[lower.tri(y)])) 
    } 
    return(apply(df, 1, vdiff)) 
} 

#TEST it out 
set.seed(10) 
(df <- data.frame(a = sample(1:100, 10), b = sample(1:100, 10), 
    c = sample(1:100, 10), d = LETTERS[1:10])) 

cdif(df) 
+0

अच्छा विचार। मेरा असली डेटाफ्रेम एक मैट्रिक्स नहीं है - क्या इसे टेक्स्ट कॉलम के साथ डेटाफ्रेम में उपयोग के लिए संशोधित किया जा सकता है? बाहरी (एक्स, एक्स, "-", drop_string = टी) की तरह कुछ? – zach

+0

फ़ंक्शन 'बाहरी' का अर्थ यह नहीं है कि आप एक मैट्रिक्स पर काम कर रहे हैं। यह सिर्फ दो वैक्टर और एक समारोह लेता है और उन दो वैक्टरों के लिए सभी संभावित संयोजनों का एक मैट्रिक्स बनाता है। यहां मैं केवल वही वेक्टर (पंक्ति) को दो बार और फ़ंक्शन घटाव '-' ऑपरेटर की आपूर्ति करता हूं। मैंने अपने स्वयं के समाधान में कुछ जोड़ा जो एक स्वयं निहित कार्य करने के लिए है जो डेटा फ्रेम पर कार्य करता है और कुछ भी नहीं है जो संख्यात्मक नहीं है। 'बाहरी' बहुत शक्तिशाली हो सकता है मैं बस कामना करता हूं कि मैं इसे और अधिक उपयोग करना याद रख सकता हूं। जहां तक ​​drop_string = टी है? ऐसी कोई किस्मत नहीं है, लेकिन 'is.numeric' क्वेरी के साथ' sapply' अच्छी तरह से काम करती है। –

+0

बहुत अच्छा है। मैं मानता हूं कि बाहरी काफी शक्तिशाली है और एक बड़े मैट्रिक्स के लिए यह प्रत्येक कॉलम या मान निर्दिष्ट करने के बजाय जाने का तरीका होगा। – zach

0

इसके बेहतर एक समारोह में लिखने के लिए और उसके बाद वैक्टर पर mapply का उपयोग करें:

f1 <- function(a,b,c){ 
d =abs(a-b) 
e =abs(b-c) 
f= abs(c-a) 
return(pmin(d,e,f)) 
} 

qq <- mapply(f1, df$a, df$b, df$c)