2012-04-09 10 views
21

私はdataframeを持っており、3つの列の値をとり、3つの値の最小の差を計算する関数を適用したいと考えています。サプリで変数として複数の列を使用

#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)) 
} 

私のようなものを探しています:私はddply使用できますが

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 

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)) 

いますが、ベクトル化バージョン書くことができます。

を私が使用して終了しました
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

私はこれが回答されている知っているが、私は実際に任意の数の列を取り、外側のアプローチを使用して、より一般化である別のアプローチを取ると思います:

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

apply(df, 1, vdiff) 

私は、これは少しクリーナーで柔軟だと思います。

EDIT:Per zachのコメント非数値の列を含むデータフレームでも機能し、数値列を削除し数値の列に対してのみ作用する、より正式な関数を提案します。

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

良いアイデア。私の実際のデータフレームは行列ではありませんが、これはテキスト列を持つデータフレームで使用するために変更できますか? outer(x、x、 " - "、drop_string = T)のようなもの? – zach

+0

関数 'outer'は、必ずしも行列を扱っているとは限りません。 2つのベクトルと関数を取り、それらの2つのベクトルのすべての可能な組み合わせの行列を作るだけです。ここでは、同じベクトル(行)を外側に2回、関数減算 ' - '演算子だけを供給します。データフレームで動作し、数値でないものを除外する自己完結型の関数を作成するために、私のソリューションに少し追加しました。 「外側」は非常に強力なことができます。私はそれをもっと使うことを覚えていればいいと思っていました。限り、drop_string = T?そのような運はありませんが、 '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) 
関連する問題