Как получить доступ к последнему значению в векторе?

Предположим, у меня есть вектор, вложенный в один или два уровня фрейма данных. Есть ли быстрый и грязный способ получить доступ к последнему значению без использования функции length()? Что-то аля PERL's $# special var?

Итак, я бы хотел что-то вроде:

dat$vec1$vec2[$#]

вместо

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

Связанный: stackoverflow.com/q/6136613/946850

krlmlr 13.02.2013 15:55

MATLAB имеет обозначение «myvariable (end-k)», где k - целое число, меньшее, чем длина вектора, который вернет элемент (length (myvariable) -k) th. Было бы неплохо, если бы в R.

EngrStudent 23.07.2014 19:48

Я ни в коем случае не эксперт по R, но быстрый гугл обнаружил следующее: <stat.ucl.ac.be/ISdidactique/Rhelp/library/pastecs/html/…> Кажется, есть "последняя" функция.

benefactual 17.09.2008 01:44
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
319
3
362 964
11

Ответы 11

Если вы ищете что-то столь же красивое, как нотация x [-1] Python, я думаю, вам не повезло. Стандартная идиома

x[length(x)]  

но достаточно просто написать функцию для этого:

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

Эта отсутствующая функция в R меня тоже раздражает!

хорошая идея предложить пример функции +1

H.Latte 31.01.2019 20:18

Обратите внимание: если вам нужны последние несколько элементов вектора, а не только последний элемент, нет необходимости делать что-либо сложное при адаптации этого решения. Векторизация R позволяет вам делать новые вещи, например, получить последние четыре элемента x, выполнив x[length(x)-0:3].

J. Mini 04.06.2020 03:07

Использую функцию tail:

tail(vector, n=1)

Приятная вещь с tail заключается в том, что он также работает с фреймами данных, в отличие от идиомы x[length(x)].

однако x [length (x [, 1]),] работает с фреймами данных или x [dim (x) [1],]

kpierce8 13.08.2009 00:25

Обратите внимание, что для фреймов данных length (x) == ncol (x), что определенно неверно, а dim (x) [1] более описательно можно записать как nrow (x).

hadley 13.08.2009 17:33

@hadley - предложение kpierce8 о x[length(x[,1]),] не является неправильным (обратите внимание на запятую в подмножестве x), но это определенно неудобно.

jbaums 28.04.2015 03:38

Обратите внимание, что мой тест ниже показывает, что это медленнее, чем x[length(x)], в среднем в 30 раз для больших векторов!

anonymous 27.02.2017 18:27

Не работает, если вы хотите добавить что-то из векторов, хотя tail(vector, n=1)-tail(vector, n=2)

Andreas Storvik Strauman 19.03.2018 20:47

Объединение идей Линделофа и Грегга Линда:

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

Работая в командной строке, я обычно опускаю n=, то есть tail(x, 1).

В отличие от last из пакета pastecs, head и tail (из utils) работают не только с векторами, но и с кадрами данных и т. д., А также могут возвращать данные "без первых / последних n элементов", например

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

(Обратите внимание, что для этого необходимо использовать head вместо tail.)

Обратите внимание, что мой тест ниже показывает, что это медленнее, чем x[length(x)], в среднем в 30 раз для больших векторов!

anonymous 27.02.2017 18:28

Другой способ - взять первый элемент перевернутого вектора:

rev(dat$vect1$vec2)[1]

Хотя это будет дорогой!

Felipe Gerard 13.10.2016 18:57

Обратите внимание, что это операция, вычислительные затраты которой линейны по длине ввода; другими словами, пока O (n), это не O (1). См. Также мой тест ниже для реальных цифр.

anonymous 27.02.2017 18:30

@anonymous Если вы не используете итератор

James 27.02.2017 22:07

@ Джеймс Верно. Но в этом случае ваш код тоже не будет работать, не так ли? Если под итератором вы имеете в виду то, что предоставляется пакетом итераторов, то (1) вы не можете использовать [1] для доступа к первому элементу и (2), хотя вы можете применить rev к итератору, он ведет себя не так, как ожидалось: он просто обрабатывает итератор как список его членов, и меняет его местами.

anonymous 01.03.2017 19:28

Я только что протестировал эти два подхода на фрейме данных с 663552 строками, используя следующий код:

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 

Итак, если вы работаете с векторами, доступ к позиции длины происходит значительно быстрее.

Почему бы не протестировать tail(strsplit(x,".",fixed=T)[[1]],1) для второго случая? Для меня главное преимущество tail в том, что вы можете написать его в одну строку. ;)

mschilli 07.07.2014 20:05

У меня есть другой способ найти последний элемент в векторе. Скажем, вектор - 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

Вот так!

Как насчет

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

Я ценю, что NROW делает то, что вы ожидаете от множества различных типов данных, но по сути это то же самое, что и a[length(a)], которого OP надеется избежать. Используя пример вложенного вектора OP, dat$vec1$vec2[NROW(dat$vec1$vec2)] все еще довольно запутан.

Gregor Thomas 19.11.2015 22:57

можно записать как nrow

Franck Dernoncourt 17.07.2017 19:34

Примечание. В отличие от nrow, NROW обрабатывает вектор как матрицу с одним столбцом.

PatrickT 16.12.2018 22:43

Чтобы ответить на этот вопрос не с эстетической, а с точки зрения производительности, я поместил все вышеперечисленные предложения через ориентир. Если быть точным, я учел предложения

  • 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)].

^ O (1) решения должны быть единственным приемлемым ответом на этот вопрос.

Kwame 10.01.2017 22:02

Спасибо, что выбрали время для анонса +1!

sam 22.09.2018 21:41

Я пробовал mylastR=function(x) {x[length(x)}. Он быстрее, чем mylast в Rcpp, но один раз медленнее, чем напрямую писать x[length(x)].

Endle_Zhenbo 18.04.2019 17:59

Пакет data.table включает функцию last

library(data.table)
last(c(1:10))
# [1] 10

В основном это снова сводится к x[[length(x)]].

Rich Scriven 07.06.2016 21:53

Пакет dplyr включает функцию last():

last(mtcars$mpg)
# [1] 21.4

В основном это снова сводится к x[[length(x)]].

Rich Scriven 07.06.2016 21:53

Аналогично под капотом, но с этим ответом вам не нужно писать свою собственную функцию last() и где-то хранить эту функцию, как это сделали несколько человек выше. Вы получаете улучшенную читаемость функции с переносимостью, исходящей от CRAN, так что кто-то другой может запустить код.

Sam Firke 07.06.2016 21:58

Также можно писать как mtcars$mpg %>% last, в зависимости от ваших предпочтений.

Keith Hughitt 04.07.2016 16:23

@RichScriven К сожалению, он значительно медленнее, чем x[[length(x)]]!

anonymous 04.04.2017 16:12

Пакет xts предоставляет функцию last:

library(xts)
a <- 1:100
last(a)
[1] 100

Другие вопросы по теме