Menambahkan nilai ke vektor kosong di R?


160

Saya mencoba belajar R dan saya tidak tahu cara menambahkan ke daftar.

Jika ini Python, saya akan melakukannya. . .

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

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

Bagaimana Anda melakukan ini dalam 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

hanya demi kejelasan, ini bukan bagaimana Anda akan melakukan ini dengan python, setidaknya jika saya mengerti Anda dengan benar. Anda bisa melakukannya vector = values; atau Anda bisa melakukan nilai vektor = vektor +. Tapi saya mungkin salah paham dengan use case Anda
Prajurit

Jawaban:


210

Menambahkan ke objek dalam loop untuk menyebabkan seluruh objek akan disalin pada setiap iterasi, yang menyebabkan banyak orang mengatakan "R lambat", atau "Loop harus dihindari".

Seperti yang BrodieG sebutkan dalam komentar: jauh lebih baik untuk pra-alokasikan vektor dengan panjang yang diinginkan, kemudian atur nilai elemen dalam loop.

Berikut adalah beberapa cara untuk menambahkan nilai ke vektor. Mereka semua berkecil hati.

Menambahkan ke vektor dalam satu lingkaran

# 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")akan menjawab pertanyaan Anda dan menghemat waktu yang Anda butuhkan untuk menulis pertanyaan ini (tetapi akan menyebabkan Anda mengembangkan kebiasaan buruk). ;-)

Perhatikan bahwa vector <- c()itu bukan vektor kosong; itu NULL. Jika Anda ingin vektor karakter kosong, gunakan vector <- character().

Pra-alokasikan vektor sebelum pengulangan

Jika Anda benar-benar harus menggunakan for loop, Anda harus mengalokasikan seluruh vektor sebelum loop. Ini akan jauh lebih cepat daripada menambahkan untuk vektor yang lebih besar.

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
Saya mencoba ini tetapi mendapat daftar NULL ketika saya mencetak (vektor)
O.rka

6
Memberi +1 untuk pengingat tentang ketidakefisienan, tapi mungkin menambahkan detail tentang cara mengatasi ( vector <- character(length(values)); for(...)?
BrodieG

20
Jika semua berkecil hati itu akan lebih baik untuk menyoroti apa yang didorong sebagai gantinya, karena ini adalah pola yang cukup umum.
baxx

pada titik ini, mungkin juga layak untuk menyebutkan buku hebat "R inferno" yang membahas vektor yang tumbuh di lingkaran 2 burns-stat.com/pages/Tutor/R_inferno.pdf
Tjebo

62

FWIW: analog dengan python menambahkan ():

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

8
Ada juga append () di R. Akan digunakan sebagai: b <- 1; b <- append(b, 2). Tetapi seperti yang Anda sebutkan, c () adalah cara yang lebih R dalam melakukan sesuatu.
juanbretti

31

Anda punya beberapa pilihan:

  • c(vector, values)

  • append(vector, values)

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

Yang pertama adalah pendekatan standar. Yang kedua memberi Anda pilihan untuk menambahkan tempat selain akhir. Yang terakhir agak berkerut tetapi memiliki keuntungan memodifikasi vector(meskipun sebenarnya, Anda bisa dengan mudah melakukannya vector <- c(vector, values).

Perhatikan bahwa dalam R Anda tidak perlu menggilir vektor. Anda bisa mengoperasikannya secara keseluruhan.

Juga, ini adalah hal yang cukup mendasar, jadi Anda harus membaca beberapa referensi .

Beberapa opsi lain berdasarkan umpan balik OP:

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

Saya melakukan sesuatu yang sedikit lebih rumit. saya perlu menambahkannya melalui for-loop karena saya memodifikasi mereka
O.rka

1
@ draconisthe0ry, mengapa Anda tidak memberikan rincian lebih lanjut tentang apa yang Anda coba lakukan?
BrodieG

1
Oh begitu! alih-alih melakukan c (vektor, nilai [i]) di dalam for loop Anda harus "vector = c (vektor, nilai [i])
O.rka

Seharusnya saya ingin menggunakan cuntuk append dataframe bukan vektor?
loretoparisi

18

Hanya demi kelengkapan, menambahkan nilai ke vektor dalam for for tidak benar-benar filosofi dalam R. R bekerja lebih baik dengan beroperasi pada vektor secara keseluruhan, seperti yang ditunjukkan oleh @BrodieG. Lihat apakah kode Anda tidak dapat ditulis ulang sebagai:

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

Output akan menjadi vektor nilai pengembalian. Anda juga dapat menggunakan lapplyjika nilai adalah daftar, bukan vektor.


8

Terkadang kita harus menggunakan loop, misalnya, ketika kita tidak tahu berapa banyak iterasi yang kita butuhkan untuk mendapatkan hasilnya. Ambil while loop sebagai contoh. Berikut adalah metode yang harus Anda hindari:

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 

Ini sangat tidak efisien karena R menyalin vektor setiap kali ditambahkan.

Cara paling efisien untuk menambahkan adalah dengan menggunakan indeks. Perhatikan bahwa saat ini saya membiarkannya mengulangi 1e7 kali, tetapi masih jauh lebih cepat daripada c.

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

Ini bisa diterima. Dan kita bisa membuatnya sedikit lebih cepat dengan mengganti [dengan [[.

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

Mungkin Anda sudah memperhatikan bahwa itu lengthbisa memakan waktu. Jika kami ganti lengthdengan penghitung:

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

Seperti yang disebutkan pengguna lain, pra-alokasi vektor sangat membantu. Tapi ini adalah trade-off antara kecepatan dan penggunaan memori jika Anda tidak tahu berapa banyak loop yang Anda butuhkan untuk mendapatkan hasilnya.

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 

Metode perantara adalah secara bertahap menambahkan blok hasil.

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

Di R, Anda dapat mencoba cara ini:

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

Apa yang Anda gunakan dalam kode python disebut daftar dalam python, dan ini tottaly berbeda dari vektor R, jika saya mendapatkan apa yang ingin Anda lakukan:

# 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))
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.