Rの空のベクトルに値を追加しますか?


159

Rを習得しようとしているのですが、リストに追加する方法がわかりません。

これがPythonだったら私はそうするでしょう。。。

#Python
vector = []
values = ['a','b','c','d','e','f','g']

for i in range(0,len(values)):
    vector.append(values[i])

Rでこれをどのように行うのですか?

#R Programming
> vector = c()
> values = c('a','b','c','d','e','f','g')
> for (i in 1:length(values))
+ #append value[i] to empty vector

わかりやすくするために、少なくとも私が正しく理解していれば、これはpythonでこれを行う方法とは異なります。あなたは単に行うことができますvector = values。または、vector = vector + valuesを実行できます。しかし、私はあなたのユースケースを誤解しているかもしれません
非公開

回答:


208

forループ内のオブジェクトに追加すると、反復ごとにオブジェクト全体がコピーされるため、多くの人が「Rが遅い」、または「Rループを回避する必要がある」と言います。

BrodieGはコメントで述べた:それは所望の長さのベクトルを事前に割り当てることがはるかに優れている、次いでループに要素の値を設定します。

以下は、ベクトルに値を追加するいくつかの方法です。それらはすべて推奨されていません。

ループ内のベクトルに追加する

# one way
for (i in 1:length(values))
  vector[i] <- values[i]
# another way
for (i in 1:length(values))
  vector <- c(vector, values[i])
# yet another way?!?
for (v in values)
  vector <- c(vector, v)
# ... more ways

help("append")あなたの質問に答えて、あなたがこの質問を書くのにかかる時間を節約できただろう(しかし、悪い習慣を身につけさせてしまうであろう);-)

vector <- c()これは空のベクターではないことに注意してください。それはですNULL。空の文字ベクトルが必要な場合は、vector <- character()

ループする前にベクトルを事前に割り当てます

forループを絶対に使用する必要がある場合は、ループの前にベクトル全体を事前に割り当てる必要があります。これは、大きなベクトルを追加するよりもはるかに高速です。

set.seed(21)
values <- sample(letters, 1e4, TRUE)
vector <- character(0)
# slow
system.time( for (i in 1:length(values)) vector[i] <- values[i] )
#   user  system elapsed 
#  0.340   0.000   0.343 
vector <- character(length(values))
# fast(er)
system.time( for (i in 1:length(values)) vector[i] <- values[i] )
#   user  system elapsed 
#  0.024   0.000   0.023 

2
私はこれを試しましたが、print(vector)のときにNULLリストを取得しました
O.rka

6
非効率性を思い出させるための+1ですが、回避策の詳細を追加することもできvector <- character(length(values)); for(...ます()?
BrodieG 2014年

20
すべてが推奨されない場合は、これがかなり一般的なパターンであるため、代わりに奨励されているものを強調表示するとよいでしょう。
baxx 2018年

この時点で、それは円2で成長ベクトルを説明します素晴らしい本「Rの地獄」に言及することも価値があるかもしれburns-stat.com/pages/Tutor/R_inferno.pdf
Tjebo

62

FWIW:pythonのappend()に類似:

b <- 1
b <- c(b, 2)

8
Rにはappend()もありますb <- 1; b <- append(b, 2)。次のように使用されます。しかし、あなたが言うように、c()は物事を行うためのよりRの方法です。
juanbretti 2017

31

いくつかのオプションがあります。

  • c(vector, values)

  • append(vector, values)

  • vector[(length(vector) + 1):(length(vector) + length(values))] <- values

最初のものは標準的なアプローチです。2つ目は、末尾以外の場所に追加するオプションを提供します。最後のものは少し歪んでいますが、変更できるという利点がvectorあります(実際には、簡単に変更できます)vector <- c(vector, values)

Rでは、ベクトルを循環する必要がないことに注意してください。それら全体を操作することができます。

また、これはかなり基本的なものなので、いくつかのリファレンスを確認する必要があります

OPフィードバックに基づくいくつかのオプション:

for(i in values) vector <- c(vector, i)

私はもう少し複雑なことをしています。私はそれらを変更しているので、forループを介してそれらを追加する必要があります
O.rka

1
@ draconisthe0ry、あなたがやろうとしていることの詳細を教えてくれませんか?
BrodieG 2014年

1
ああなるほど!forループでc(vector、values [i])を実行する代わりに、「vector = c(vector、values [i])
O.rka

cベクターの代わりにデータフレームを追加するために使用したいと思いますか?
loretoparisi

18

完全を期すために、forループでベクトルに値を追加することは、実際にはRの哲学ではありません。コードを次のように書き換えられないかどうかを確認します。

ouput <- sapply(values, function(v) return(2*v))

出力は戻り値のベクトルになります。lapply値がベクトルではなくリストの場合にも使用できます。


8

たとえば、結果を取得するために必要な反復回数がわからない場合など、ループを使用する必要がある場合があります。例として、whileループを取り上げます。以下は絶対に避けるべき方法です:

a=numeric(0)
b=1
system.time(
  {
    while(b<=1e5){
      b=b+1
      a<-c(a,pi)
    }
  }
)
# user  system elapsed 
# 13.2     0.0    13.2 

a=numeric(0)
b=1
system.time(
  {
    while(b<=1e5){
      b=b+1
      a<-append(a,pi)
    }
  }
)
# user  system elapsed 
# 11.06    5.72   16.84 

Rは追加するたびにベクトルをコピーするため、これらは非常に非効率的です。

追加する最も効率的な方法は、インデックスを使用することです。今回は1e7回反復させましたが、それでもまだずっと高速ですc

a=numeric(0)
system.time(
  {
    while(length(a)<1e7){
      a[length(a)+1]=pi
    }
  }
)
# user  system elapsed 
# 5.71    0.39    6.12  

これは許容範囲です。そして、私たちは置き換えることによって、少し速くそれを作ることができる[[[

a=numeric(0)
system.time(
  {
    while(length(a)<1e7){
      a[[length(a)+1]]=pi
    }
  }
)
# user  system elapsed 
# 5.29    0.38    5.69   

length時間がかかることに気づいたかもしれません。lengthカウンターに置き換えると:

a=numeric(0)
b=1
system.time(
  {
    while(b<=1e7){
      a[[b]]=pi
      b=b+1
    }
  }
)
# user  system elapsed 
# 3.35    0.41    3.76

他のユーザーが述べたように、ベクトルの事前割り当ては非常に役立ちます。しかし、結果を得るために必要なループの数がわからない場合、これは速度とメモリ使用量の間のトレードオフです。

a=rep(NaN,2*1e7)
b=1
system.time(
  {
    while(b<=1e7){
      a[[b]]=pi
      b=b+1
    }
    a=a[!is.na(a)]
  }
)
# user  system elapsed 
# 1.57    0.06    1.63 

中間的な方法は、結果のブロックを徐々に追加することです。

a=numeric(0)
b=0
step_count=0
step=1e6
system.time(
  {
    repeat{
      a_step=rep(NaN,step)
      for(i in seq_len(step)){
        b=b+1
        a_step[[i]]=pi
        if(b>=1e7){
          a_step=a_step[1:i]
          break
        }
      }
      a[(step_count*step+1):b]=a_step
      if(b>=1e7) break
      step_count=step_count+1
    }
  }
)
#user  system elapsed 
#1.71    0.17    1.89

2

Rでは、次のように試すことができます。

X = NULL
X
# NULL
values = letters[1:10]
values
# [1] "a" "b" "c" "d" "e" "f" "g" "h" "i" "j"
X = append(X,values)
X
# [1] "a" "b" "c" "d" "e" "f" "g" "h" "i" "j"
X = append(X,letters[23:26])
X
# [1] "a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "w" "x" "y" "z"

2
> vec <- c(letters[1:3]) # vec <- c("a","b","c") ; or just empty vector: vec <- c()

> values<- c(1,2,3)

> for (i in 1:length(values)){
      print(paste("length of vec", length(vec))); 
      vec[length(vec)+1] <- values[i]  #Appends value at the end of vector
  }

[1] "length of vec 3"
[1] "length of vec 4"
[1] "length of vec 5"

> vec
[1] "a" "b" "c" "1" "2" "3"

0

あなたがPythonコードで使用しているものはPythonではリストと呼ばれ、あなたがやりたいことを私が得た場合、それはRベクトルとは全く異なります:

# you can do like this if you'll put them manually  
v <- c("a", "b", "c")

# if your values are in a list 
v <- as.vector(your_list)

# if you just need to append
v <- append(v, value, after=length(v))
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.