2015-09-16 16 views
7

私はとても単純な関数を作成しようとしています。基本的に私はt$Cのすべての要素を自分のコードのif thenステートメントに従って変更し、他は同じままにします。だからここに私のコード:rの簡単な関数

set.seed(20) 
x1=rnorm(100) 
x2=rnorm(100) 
x3=rnorm(100) 
t=data.frame(a=x1,b=x1+x2,c=x1+x2+x3) 
fun1=function(multi1,multi2) 
{ 
    v=t$c 
    s=c() 
    for (i in v) 
    { 
    if (i<0) 
    { 
     s[i]=i*multi1 
    } 
    else if(i>0) 
    { 
     s[i]=i*multi2 
    } 
    } 

    return(s) 
} 

fun1(multi1=0.5,multi2=2) 

しかし、それは私にちょうどいくつかの数字を与えた。私はいくつかの愚かなミスをしたかもしれないと感じましたが、私は理解できませんでした。

+1

はい、理想的な出力を表示してください。私たちがそれを得ると、我々は手伝ってみることができます。しかし、一般的なこととして、この 'x1 < - rnorm(100)'のような割り当てを書くことを考えてください。 –

+0

0の値をNAにするか、0を0にしますか? – Dason

+0

コメントのためにちょっとショーンありがとう。私は< - と=は同じことだと思っていました。彼らはそうではありませんか? – Jade

答えて

10

t1; drこの操作はベクトル化できます。 0またはNAの値だけを残したい場合は、次の方法を使用できます。

with(t, c * ifelse(c < 0, 0.5, ifelse(c > 0, 2, 1))) 

一方の側(たとえば、プラス側)に含める場合は、さらに簡単です。

with(t, c * ifelse(c < 0, 0.5, 2)) 

は限り、あなたのループが行くように、あなたはそこにいくつかの問題を持っています。

最初に、sの10進数のインデックスを作成していたため、計算にエラーが発生する可能性があります。これは結果ベクトルが非常に短い理由でもあります。ループ内でインデックスを作成すると、インデックスが整数値に移動し、その一部が繰り返されたため、sが非常に短くなりました。

実際の一意のインデックス長はこのような何か行ってきました - 1が繰り返されているので、簡単な例として、

s[c(1, 2, 1, 1)] <- something 

length(unique(as.integer(t$c))) 
# [1] 9 

そして、あなたが得た結果を、唯一の1と2をインデックス変更されました。これはあなたのループで起こっていたことです。さらに

x <- 1:5 
x[1.2] 
# [1] 1 
x[1.99] 
# [1] 1 

次に、我々はベクトルsを割り当てたより低い通知として示さ。結果のベクトルの長さがvと同じであることがわかっているので、これを行うことができます。これは、ループ内にベクターを構築するのではなく、推奨される、より効率的な方法です。

移動すると、これを修正するためにfor(i in v)for(i in seq_along(v))に変更しました。今度はiのシーケンスでインデックスを作成しています。次に同じ方法でvを索引付けする必要があります。最後に、if()ステートメント内の同じインデックスに代入するのではなく、s[i] <- if(...を割り当てることができます。

0や、vNAなど)に表示される可能性のある他の値を考慮していないことにも注意してください。私は最終的にelseを追加しました。ここでは、これらの値だけを残しています。必要に応じて変更してください。さらに、地球環境に行く代わりにt$cを引数として渡して、この関数をより一般的なものにすることができます(その提案に対する@ShawnMehanの功績)。ここでは改訂版です:

fun1 <- function(vec, multi1, multi2) { 
    s <- vector("numeric", length(vec)) 
    for (i in seq_along(vec)) { 
     s[i] <- if (vec[i] < 0) { 
      vec[i] * multi1 
     } else if(vec[i] > 0) { 
      vec[i] * multi2 
     } else { 
      vec[i] 
     } 
    } 
    return(s) 
} 

は、だから今、私たちは、長さ100結果

x <- fun1(t$c, 0.5, 2) 
str(x) 
# num [1:100] 2.657 -0.949 7.423 -0.749 5.664 ... 

を持って、私はあなたがループの書き方を学習している把握ので、私はこの長い説明を書きました。 Rでは、この操作全体をベクトル化して1行のコードにまとめることができます。次の行は、fun1(t$c, 0.5, 2)と同じ結果になります。

with(t, c * ifelse(c < 0, 0.5, ifelse(c > 0, 2, 1))) 

計算監督を捕まえるために@Frankに感謝します。

これはすべて意味があることを願っています。時には説明や専門用語でうまくやっていないこともあります。ご不明な点がございましたら、ご意見ください。

+0

awesome。私が追加しようとしていたのは、入力のための関数呼び出しに3番目のパラメータを置くことでした。すべての可能な列を再利用できるように 'x < - fun1(t $ c、0.5,2)' 'fun1 < - 関数(input_vector、multi1、multi2)'を介して。 –

+0

良いアイデア。私はそれを追加します –

+0

私は@ ShawnMehanに同意しますが、これはコードのクリーンアップの良い仕事だと思います。データは関数への入力でなければなりません。 Rには明らかに最適ではありませんが、これはループ処理ではなくかなり簡単にベクトル化できるためです。 – Dason

関連する問題