ผนวกค่ากับเวกเตอร์เปล่าใน R?


160

ฉันพยายามเรียนรู้ R และฉันไม่สามารถหาวิธีผนวกเข้ากับรายการ

ถ้านี่เป็นงูหลามฉันจะ . .

#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

เพียงเพื่อความชัดเจนนี่ไม่ใช่วิธีที่คุณจะทำในหลามอย่างน้อยถ้าฉันเข้าใจคุณถูกต้อง คุณก็สามารถทำvector = values; หรือคุณสามารถทำค่า vector = vector + แต่ฉันอาจจะเข้าใจผิดกรณีที่คุณใช้งาน
ส่วนตัว

คำตอบ:


209

การต่อท้ายวัตถุในลูปทำให้วัตถุทั้งหมดถูกคัดลอกในการวนซ้ำทุกครั้งซึ่งทำให้ผู้คนจำนวนมากพูดว่า "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 for loop อย่างแน่นอนคุณควรจัดสรร vector ทั้งหมดก่อนการวนซ้ำ นี่จะเร็วกว่าการผนวกเวกเตอร์ที่มีขนาดใหญ่กว่ามาก

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
ฉันลองสิ่งนี้ แต่มีรายการ NULL เมื่อฉันพิมพ์ (เวกเตอร์)
O.rka

6
+1 เพื่อเตือนความจำเกี่ยวกับความไม่มีประสิทธิภาพ แต่อาจเพิ่มรายละเอียดเกี่ยวกับวิธีแก้ไข ( vector <- character(length(values)); for(...)?
BrodieG

20
หากหมดกำลังใจก็น่ายินดีที่จะเน้นสิ่งที่ได้รับการสนับสนุนแทนเนื่องจากนี่เป็นรูปแบบที่ใช้กันโดยทั่วไป
baxx

ณ จุดนี้มันอาจคุ้มค่าที่จะกล่าวถึงหนังสือยอดเยี่ยม "R inferno" ซึ่งกล่าวถึงเวกเตอร์ที่กำลังเติบโตในวงกลม 2 burns-stat.com/pages/Tutor/R_inferno.pdf
Tjebo

62

FWIW: คล้ายกับส่วนต่อท้ายของ python ():

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

8
นอกจากนี้ยังมีผนวก ()b <- 1; b <- append(b, 2)ในอาร์จะถูกใช้เป็น: แต่เมื่อคุณพูดถึงc ()เป็นวิธีการทำสิ่ง R เพิ่มเติม
juanbretti

31

คุณมีตัวเลือกน้อย:

  • c(vector, values)

  • append(vector, values)

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

คนแรกคือวิธีการมาตรฐาน ส่วนที่สองให้ตัวเลือกในการผนวกที่อื่นที่ไม่ใช่จุดสิ้นสุด คนสุดท้ายเป็นบิตบิดเบี้ยว แต่มีข้อได้เปรียบของการปรับเปลี่ยนvector( vector <- c(vector, values)แต่จริงๆคุณสามารถได้อย่างง่ายดายเพียงทำ

โปรดสังเกตว่าใน R คุณไม่จำเป็นต้องวนรอบเวกเตอร์ คุณสามารถใช้งานได้ทั้งหมด

นอกจากนี้เป็นสิ่งพื้นฐานที่เป็นธรรมดังนั้นคุณควรจะไปผ่านบางส่วนของการอ้างอิง

ตัวเลือกเพิ่มเติมตาม OP feedback:

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

ฉันกำลังทำอะไรบางอย่างที่ซับซ้อนกว่าเล็กน้อย ฉันต้องการผนวกพวกเขาผ่าน for-loop เพราะฉันแก้ไขพวกเขา
O.rka

1
@ draconisthe0ry ทำไมคุณไม่ให้รายละเอียดเพิ่มเติมเกี่ยวกับสิ่งที่คุณพยายามจะทำล่ะ
BrodieG

1
อ้อเข้าใจแล้ว! แทนที่จะทำ c (เวกเตอร์, ค่า [i]) ในลูป for คุณต้อง "vector = c (vector, ค่า [i])
O.rka

ฉันควรจะใช้cเพื่อผนวกดาต้าเฟรมแทนการใช้เวกเตอร์หรือไม่?
loretoparisi

18

เพียงเพื่อประโยชน์ของความสมบูรณ์การต่อท้ายค่าของเวกเตอร์ในการวนรอบนั้นไม่ใช่ปรัชญาใน R. R ที่ทำงานได้ดีกว่าโดยการใช้เวกเตอร์โดยรวมตามที่ @BrodieG ชี้ให้เห็น ดูว่ารหัสของคุณไม่สามารถเขียนใหม่เป็น:

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

เอาต์พุตจะเป็นเวกเตอร์ของค่าส่งคืน คุณสามารถใช้lapplyถ้าค่าเป็นรายการแทนที่จะเป็นเวกเตอร์


8

บางครั้งเราต้องใช้ลูปตัวอย่างเช่นเมื่อเราไม่รู้จำนวนการวนซ้ำที่เราต้องการเพื่อให้ได้ผลลัพธ์ ใช้ในขณะที่ลูปเป็นตัวอย่าง ด้านล่างเป็นวิธีที่คุณควรหลีกเลี่ยงอย่างยิ่ง:

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

สิ่งที่คุณใช้ในรหัสไพ ธ อนนั้นเรียกว่ารายการในไพ ธ อนและมันก็มี tottaly แตกต่างจากเวกเตอร์ 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.