R'deki boş vektöre değer eklensin mi?


160

R öğrenmeye çalışıyorum ve bir listeye nasıl ekleneceğini anlayamıyorum.

Eğer bu Python olsaydı yapardım. . .

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

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

Bunu R'de nasıl yaparsın?

#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

sadece netlik uğruna, bunu en azından doğru şekilde anlarsam, bunu python'da böyle yapmazsınız. basitçe yapabilirdiniz vector = values; veya vektör = vektör + değerleri yapabilirsiniz. Ama kullanım durumunuzu yanlış anlayabilirim
Private

Yanıtlar:


210

For döngüsünde bir nesneye eklemek, tüm nesnenin her yinelemede kopyalanmasına neden olur, bu da birçok insanın "R yavaş" veya "R döngülerinden kaçınılması" gerektiğini söyler.

BrodieG'nin yorumlarda belirttiği gibi : istenen uzunlukta bir vektörü önceden ayırmak, daha sonra döngüdeki eleman değerlerini ayarlamak çok daha iyidir.

İşte bir vektöre değer eklemenin birkaç yolu. Hepsi cesaretini kırdı.

Döngüdeki bir vektöre ekleme

# 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")sorunuzu yanıtlar ve bu soruyu yazmanız için gereken zamanı kurtarır (ancak kötü alışkanlıklar geliştirmenize neden olur). ;-)

vector <- c()Boş bir vektör olmadığını unutmayın ; öyle NULL. Boş bir karakter vektörü istiyorsanız, kullanın vector <- character().

Döngüden önce vektörü önceden ayırın

Eğer varsa mutlaka gereken döngü için kullanmak, sen döngü önce tüm vektör önceden tahsis edilmelidir. Bu, daha büyük vektörlere eklenenden çok daha hızlı olacaktır.

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
Bunu denedim ama yazdırdığımda (vektör) NULL bir liste aldım
O.rka

6
Verimsizlik hakkında hatırlatma için +1, ancak belki ( vector <- character(length(values)); for(...) etrafında nasıl çalışacağınıza dair ayrıntılar ekleyebilirsiniz ?
BrodieG

20
Her şeyden vazgeçilirse, bunun yerine teşvik edilenleri vurgulamak güzel olurdu, çünkü bu oldukça yaygın bir modeldir.
baxx


62

FWIW: python ekine () benzer:

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

8
Orada da ekleme () olarak kullanılabilir Will R. içinde: b <- 1; b <- append(b, 2). Ama belirttiğiniz gibi, c () bir şeyler yapmanın daha R yoludur.
juanbretti

31

Birkaç seçeneğiniz var:

  • c(vector, values)

  • append(vector, values)

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

Birincisi standart yaklaşımdır. İkincisi, sondan başka bir yere ekleme seçeneği sunar. Sonuncusu biraz bükülmüş ama değiştirme avantajına sahip vector(gerçekten de kolayca yapabilirsiniz vector <- c(vector, values).

R'de vektörler arasında dolaşmanıza gerek olmadığına dikkat edin. Onları tamamen çalıştırabilirsiniz.

Ayrıca, bu oldukça temel şeyler, bu yüzden bazı referanslardan geçmelisiniz .

OP geri bildirimini temel alan bazı seçenekler:

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

biraz daha karmaşık bir şey yapıyorum tho. Onları değiştirdiğim için onları for-loop yoluyla eklemeniz gerekiyor
O.rka

1
@ draconisthe0ry, neden yapmaya çalıştığınız hakkında daha fazla ayrıntı vermiyorsunuz?
BrodieG

1
Ah anlıyorum! for döngüsünde c (vektör, değerler [i]) yapmak yerine "vector = c (vektör, değerler [i])
O.rka

cvarsayalım vektörler yerine dataframe eklemek için kullanmak istiyorum ?
loretoparisi

18

Sadece tamlık uğruna, for döngüsünde bir vektöre değer eklemek aslında R'deki felsefe değildir. R, @BrodieG'nin işaret ettiği gibi vektörler üzerinde bir bütün olarak çalışarak daha iyi çalışır. Kodunuzun şu şekilde yeniden yazılamayacağını kontrol edin:

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

Çıktı, dönüş değerlerinin bir vektörü olacaktır. lapplyDeğerler vektör yerine bir liste ise de kullanabilirsiniz .


8

Bazen döngüleri kullanmak zorundayız, örneğin, sonucu almak için kaç yineleme gerektiğini bilmediğimizde. Süre döngülerini örnek olarak alalım. Kesinlikle kaçınmanız gereken yöntemler şunlardır:

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 

Bunlar çok verimsizdir, çünkü R her eklediğinde vektörü kopyalar.

Eklemenin en etkili yolu dizin kullanmaktır. Bu sefer 1e7 kez yinelemesine izin verdiğimi unutmayın, ancak yine de çok daha hızlı c.

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

Bu kabul edilebilir. Ve biz değiştirerek biraz daha hızlı yapabilir [ile [[.

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

Belki lengthde bunun zaman alıcı olabileceğini fark ettiniz . Bir sayaçla değiştirirsek 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

Diğer kullanıcıların belirttiği gibi, vektörün önceden tahsis edilmesi çok yararlıdır. Ancak sonuç almak için kaç döngüye ihtiyacınız olduğunu bilmiyorsanız, bu, hız ve bellek kullanımı arasındaki bir dengedir.

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 

Ara yöntem yavaş yavaş sonuç blokları eklemektir.

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'de şu şekilde deneyebilirsiniz:

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 kodunda kullandığınız şey, python'da bir liste olarak adlandırılır ve ne yapmak istediğinizi alırsam, R vektörlerinden tamamen farklıdı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))
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.