วิธีเข้าถึงค่าสุดท้ายในเวกเตอร์


290

สมมติว่าฉันมีเวกเตอร์ที่ซ้อนในดาต้าเฟรมหนึ่งหรือสองระดับ มีวิธีที่รวดเร็วและสกปรกในการเข้าถึงค่าสุดท้ายโดยไม่ใช้length()ฟังก์ชั่นหรือไม่? มีอะไรเป็น$#พิเศษของ PERL PER บ้าง?

ดังนั้นฉันต้องการบางสิ่งเช่น:

dat$vec1$vec2[$#]

แทน

dat$vec1$vec2[length(dat$vec1$vec2)]

1
ฉันไม่เคยเป็นผู้เชี่ยวชาญ R มาก่อน แต่ Google เปิดใช้งานอย่างรวดเร็ว: < stat.ucl.ac.be/ISdidactique/Rhelp/library/pastecs/html/ … > ดูเหมือนจะมีฟังก์ชั่น "สุดท้าย"
ประโยชน์

ที่เกี่ยวข้อง: stackoverflow.com/q/6136613/946850
krlmlr

1
MATLAB มีสัญกรณ์ "myvariable (end-k)" โดยที่ k เป็นจำนวนเต็มน้อยกว่าความยาวของเวกเตอร์ที่จะส่งกลับองค์ประกอบ (ความยาว (myvariable) -k) th นั่นคงจะดีถ้ามีใน R.
EngrStudent

คำตอบ:


369

ฉันใช้tailฟังก์ชั่น:

tail(vector, n=1)

สิ่งที่ดีด้วยtailคือมันทำงานบน dataframes เหมือนกันกับx[length(x)]สำนวน


5
อย่างไรก็ตาม x [ความยาว (x [, 1]),] ทำงานบน dataframes หรือ x [dim (x) [1],]
kpierce8

29
โปรดทราบว่าสำหรับเฟรมข้อมูลความยาว (x) == ncol (x) ดังนั้นมันจึงผิดอย่างแน่นอนและสลัว (x) [1] สามารถเขียน nrow (x) ได้อย่างชัดเจนยิ่งขึ้น
hadley

2
@Hadley - ข้อเสนอแนะของ kpierce8 เกี่ยวกับx[length(x[,1]),]ไม่ผิด (โปรดสังเกตเครื่องหมายจุลภาคในxชุดย่อย) แต่ก็ไม่แน่นอนอย่างแน่นอน
jbaums

4
โปรดทราบว่าเกณฑ์มาตรฐานของฉันด้านล่างแสดงให้เห็นว่าสิ่งนี้ช้ากว่าx[length(x)]โดยเฉลี่ย 30 สำหรับเวกเตอร์ขนาดใหญ่!
ไม่ระบุชื่อ

1
ใช้งานไม่ได้หากคุณต้องการเพิ่มสิ่งต่าง ๆ จากเวกเตอร์tail(vector, n=1)-tail(vector, n=2)
Andreas Storvik Strauman

181

เพื่อที่จะตอบไม่ได้นี้จากจุดสุนทรียภาพ แต่ประสิทธิภาพที่มุ่งเน้นในมุมมองของฉันได้ใส่ทุกคำแนะนำข้างต้นผ่านเกณฑ์มาตรฐาน เพื่อความแม่นยำฉันได้พิจารณาข้อเสนอแนะ

  • x[length(x)]
  • mylast(x)ซึ่งmylastเป็นฟังก์ชั่น C ++ ที่ใช้งานผ่าน Rcpp
  • tail(x, n=1)
  • dplyr::last(x)
  • x[end(x)[1]]]
  • rev(x)[1]

และนำไปใช้กับเวกเตอร์สุ่มขนาดต่างๆ (10 ^ 3, 10 ^ 4, 10 ^ 5, 10 ^ 6 และ 10 ^ 7) ก่อนที่เราจะดูตัวเลขฉันคิดว่ามันควรชัดเจนว่าอะไรก็ตามที่ช้าลงอย่างเห็นได้ชัดด้วยขนาดอินพุตที่มากขึ้น (เช่นสิ่งที่ไม่ใช่ O (1)) ไม่ใช่ตัวเลือก นี่คือรหัสที่ฉันใช้:

Rcpp::cppFunction('double mylast(NumericVector x) { int n = x.size(); return x[n-1]; }')
options(width=100)
for (n in c(1e3,1e4,1e5,1e6,1e7)) {
  x <- runif(n);
  print(microbenchmark::microbenchmark(x[length(x)],
                                       mylast(x),
                                       tail(x, n=1),
                                       dplyr::last(x),
                                       x[end(x)[1]],
                                       rev(x)[1]))}

มันทำให้ฉัน

Unit: nanoseconds
           expr   min      lq     mean  median      uq   max neval
   x[length(x)]   171   291.5   388.91   337.5   390.0  3233   100
      mylast(x)  1291  1832.0  2329.11  2063.0  2276.0 19053   100
 tail(x, n = 1)  7718  9589.5 11236.27 10683.0 12149.0 32711   100
 dplyr::last(x) 16341 19049.5 22080.23 21673.0 23485.5 70047   100
   x[end(x)[1]]  7688 10434.0 13288.05 11889.5 13166.5 78536   100
      rev(x)[1]  7829  8951.5 10995.59  9883.0 10890.0 45763   100
Unit: nanoseconds
           expr   min      lq     mean  median      uq    max neval
   x[length(x)]   204   323.0   475.76   386.5   459.5   6029   100
      mylast(x)  1469  2102.5  2708.50  2462.0  2995.0   9723   100
 tail(x, n = 1)  7671  9504.5 12470.82 10986.5 12748.0  62320   100
 dplyr::last(x) 15703 19933.5 26352.66 22469.5 25356.5 126314   100
   x[end(x)[1]] 13766 18800.5 27137.17 21677.5 26207.5  95982   100
      rev(x)[1] 52785 58624.0 78640.93 60213.0 72778.0 851113   100
Unit: nanoseconds
           expr     min        lq       mean    median        uq     max neval
   x[length(x)]     214     346.0     583.40     529.5     720.0    1512   100
      mylast(x)    1393    2126.0    4872.60    4905.5    7338.0    9806   100
 tail(x, n = 1)    8343   10384.0   19558.05   18121.0   25417.0   69608   100
 dplyr::last(x)   16065   22960.0   36671.13   37212.0   48071.5   75946   100
   x[end(x)[1]]  360176  404965.5  432528.84  424798.0  450996.0  710501   100
      rev(x)[1] 1060547 1140149.0 1189297.38 1180997.5 1225849.0 1383479   100
Unit: nanoseconds
           expr     min        lq        mean    median         uq      max neval
   x[length(x)]     327     584.0     1150.75     996.5     1652.5     3974   100
      mylast(x)    2060    3128.5     7541.51    8899.0     9958.0    16175   100
 tail(x, n = 1)   10484   16936.0    30250.11   34030.0    39355.0    52689   100
 dplyr::last(x)   19133   47444.5    55280.09   61205.5    66312.5   105851   100
   x[end(x)[1]] 1110956 2298408.0  3670360.45 2334753.0  4475915.0 19235341   100
      rev(x)[1] 6536063 7969103.0 11004418.46 9973664.5 12340089.5 28447454   100
Unit: nanoseconds
           expr      min         lq         mean      median          uq       max neval
   x[length(x)]      327      722.0      1644.16      1133.5      2055.5     13724   100
      mylast(x)     1962     3727.5      9578.21      9951.5     12887.5     41773   100
 tail(x, n = 1)     9829    21038.0     36623.67     43710.0     48883.0     66289   100
 dplyr::last(x)    21832    35269.0     60523.40     63726.0     75539.5    200064   100
   x[end(x)[1]] 21008128 23004594.5  37356132.43  30006737.0  47839917.0 105430564   100
      rev(x)[1] 74317382 92985054.0 108618154.55 102328667.5 112443834.0 187925942   100

สิ่งนี้จะห้ามสิ่งที่เกี่ยวข้องrevหรือendเนื่องจากไม่ชัดเจนO(1)(และการแสดงออกที่เกิดขึ้นจะถูกประเมินในแบบที่ไม่ขี้เกียจ) tailและdplyr::lastไม่ไกลจากการเป็นO(1)แต่พวกเขายังช้ากว่าmylast(x)และมากx[length(x)]มาก เนื่องจากmylast(x)จะช้ากว่าx[length(x)]และให้ผลประโยชน์ไม่มี ( แต่ก็กำหนดเองและไม่ได้จัดการกับเวกเตอร์ที่ว่างเปล่าได้อย่างสง่างาม) ผมคิดว่าคำตอบเป็นที่ชัดเจน: ใช้โปรดx[length(x)]


11
^ O (1) คำตอบควรเป็นคำตอบที่ยอมรับได้ในคำถามนี้เท่านั้น
Kwame

2
ขอบคุณสำหรับการกำหนดเวลา anon +1 ทั้งหมด!
Sam

1
ฉันพยายามmylastR=function(x) {x[length(x)}มันเร็วกว่าmylastใน Rcpp แต่ช้ากว่าการเขียนหนึ่งครั้งx[length(x)]โดยตรง
Endle_Zhenbo

115

หากคุณกำลังมองหาบางสิ่งที่ดีพอ ๆ กับสัญกรณ์ Python x [-1] ฉันคิดว่าคุณไม่มีโชค สำนวนมาตรฐานคือ

x[length(x)]  

แต่มันง่ายพอที่จะเขียนฟังก์ชั่นเพื่อทำสิ่งนี้:

last <- function(x) { return( x[length(x)] ) }

ฟีเจอร์ที่หายไปใน R ทำให้ฉันรำคาญเช่นกัน!


3
เป็นความคิดที่ดีที่จะเสนอฟังก์ชั่นตัวอย่าง +1
H.Latte

โปรดทราบว่าหากคุณต้องการองค์ประกอบสองสามชิ้นสุดท้ายของเวกเตอร์แทนที่จะเป็นองค์ประกอบสุดท้ายคุณไม่จำเป็นต้องทำอะไรที่ซับซ้อนเมื่อปรับโซลูชันนี้ อาร์เอส vectorization ช่วยให้คุณสามารถทำสิ่ง neet ต้องการได้รับในช่วงสี่องค์ประกอบของโดยการทำx x[length(x)-0:3]
J. Mini

46

การรวมความคิดของlindelofและGregg Lind :

last <- function(x) { tail(x, n = 1) }

การทำงานที่พรอมต์ฉันมักจะละเว้นเช่นn=tail(x, 1)

แตกต่างlastจากpastecsแพคเกจheadและtail(จากutils ) ทำงานไม่เพียง แต่บนเว็กเตอร์เท่านั้น แต่ยังอยู่ในเฟรมข้อมูล ฯลฯ และยังสามารถส่งคืนข้อมูล " โดยไม่มีองค์ประกอบแรก / สุดท้าย " เช่น

but.last <- function(x) { head(x, n = -1) }

(โปรดทราบว่าคุณต้องใช้headสิ่งนี้แทนtail)


7
โปรดทราบว่าเกณฑ์มาตรฐานของฉันด้านล่างแสดงให้เห็นว่าสิ่งนี้ช้ากว่าx[length(x)]โดยเฉลี่ย 30 สำหรับเวกเตอร์ขนาดใหญ่!
ไม่ระบุชื่อ

19

dplyrแพคเกจรวมถึงฟังก์ชั่นlast():

last(mtcars$mpg)
# [1] 21.4

4
โดยทั่วไปแล้วจะเดือดลงไปx[[length(x)]]อีกครั้ง
Rich Scriven

6
คล้ายกันภายใต้ประทุน แต่ด้วยคำตอบนี้คุณไม่จำเป็นต้องเขียนฟังก์ชั่นของคุณเองlast()และเก็บฟังก์ชั่นนั้นไว้ที่ใดที่หนึ่งเหมือนกับหลาย ๆ คนที่ได้ทำไปแล้ว คุณจะได้รับฟังก์ชั่นการอ่านที่ปรับปรุงให้ดีขึ้นโดยความสามารถในการพกพาของมันมาจาก CRAN เพื่อให้บุคคลอื่นสามารถรันโค้ดได้
Sam Firke

1
ยังสามารถเขียนเป็นmtcars$mpg %>% lastขึ้นอยู่กับความชอบของคุณ
Keith Hughitt

1
@ RichScriven น่าเสียดายที่มันช้ากว่าx[[length(x)]]มาก!
ไม่ระบุตัวตน

18

ฉันเพิ่งเกณฑ์สองวิธีนี้ในกรอบข้อมูลกับ 663,552 แถวโดยใช้รหัสต่อไปนี้:

system.time(
  resultsByLevel$subject <- sapply(resultsByLevel$variable, function(x) {
    s <- strsplit(x, ".", fixed=TRUE)[[1]]
    s[length(s)]
  })
  )

 user  system elapsed 
  3.722   0.000   3.594 

และ

system.time(
  resultsByLevel$subject <- sapply(resultsByLevel$variable, function(x) {
    s <- strsplit(x, ".", fixed=TRUE)[[1]]
    tail(s, n=1)
  })
  )

   user  system elapsed 
 28.174   0.000  27.662 

สมมติว่าคุณทำงานกับเวกเตอร์การเข้าถึงตำแหน่งความยาวนั้นเร็วกว่ามาก


3
ทำไมไม่ทดสอบtail(strsplit(x,".",fixed=T)[[1]],1)สำหรับกรณีที่สอง? สำหรับฉันข้อได้เปรียบหลักของtailคือคุณสามารถเขียนมันในหนึ่งบรรทัด ;)
mschilli

13

อีกวิธีคือใช้องค์ประกอบแรกของเวกเตอร์ที่กลับด้าน:

rev(dat$vect1$vec2)[1]

7
นี้จะมีราคาแพงแม้ว่า!
Felipe Gerard

1
โปรดทราบว่านี่เป็นการดำเนินการที่ต้นทุนการคำนวณเป็นเชิงเส้นตรงตามความยาวของอินพุต กล่าวอีกนัยหนึ่งขณะที่ O (n) ไม่ใช่ O (1) ดูมาตรฐานของฉันด้านล่างสำหรับตัวเลขจริง
ไม่ระบุชื่อ

@anonymous เว้นแต่คุณจะใช้ตัววนซ้ำ
James

@ James ถูกต้อง แต่ในกรณีนั้นรหัสของคุณยังใช้งานไม่ได้ใช่ไหม หากโดย iterator คุณหมายถึงสิ่งที่จัดทำโดยแพ็คเกจตัววนซ้ำดังนั้น (1) คุณไม่สามารถใช้[1]เพื่อเข้าถึงองค์ประกอบแรกและ (2) ในขณะที่คุณสามารถใช้revกับตัววนซ้ำได้มันจะไม่ทำงานตามที่คาดไว้ รายชื่อสมาชิกและกลับรายการ
ไม่ระบุชื่อ


10

ฉันมีวิธีอื่นในการค้นหาองค์ประกอบสุดท้ายในเวกเตอร์ aบอกว่าเวกเตอร์คือ

> a<-c(1:100,555)
> end(a)      #Gives indices of last and first positions
[1] 101   1
> a[end(a)[1]]   #Gives last element in a vector
[1] 555

ไปแล้ว!


8

เกี่ยวกับอะไร

> a <- c(1:100,555)
> a[NROW(a)]
[1] 555

1
ฉันขอบคุณที่NROWทำสิ่งที่คุณคาดหวังกับชนิดข้อมูลที่แตกต่างกันมากมาย แต่โดยพื้นฐานแล้วมันก็เหมือนกับa[length(a)]OP ที่หวังว่าจะหลีกเลี่ยง การใช้ตัวอย่างของเวกเตอร์ที่ซ้อนกันอยู่ของ OP dat$vec1$vec2[NROW(dat$vec1$vec2)]ยังคงเป็นสิ่งที่ค่อนข้างยุ่ง
Gregor Thomas

1
อาจเขียนเป็นnrow
Franck Dernoncourt

2
หมายเหตุ: แตกต่างnrow, NROWถือว่าเวกเตอร์เป็นเมทริกซ์ 1 คอลัมน์
PatrickT

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.