У меня проблема с векторизацией. Скажем, у меня есть вектор x <- c(0,0,1,0,1,1,0)
, я хочу получить вектор (1,0,1,1)
или удалить все 0 с первой точки до первой ненулевой точки и все 0 с последней ненулевой точки до последней точки . Обычно это легко, но сложность в том, что я не могу использовать циклы (for, while и т. д.). По сути, я должен «векторизовать» весь алгоритм. Кто-нибудь поможет, пожалуйста?
Векторизировать мышление
Ответы (2)
Я думаю, вы можете попробовать это. Спасибо за @JacobH
комментарий, так будет быстрее.
x <- c(0,0,1,0,1,1,0)
zeros <- which(x > 0)
x[zeros[1]:tail(zeros, n = 1)]
выход
[1] 1 0 1 1
person
Zihu Guo
schedule
18.06.2015
Небольшие изменения в подходе Цзыху Го. Инициализировать вызов, к которому. то есть
zeros=which(x > 0); x[zeros[1]:tail(zeros, n=1)]
- person Jacob H; 18.06.2015
Мое дополнение делает его более читабельным. Однако его важность гораздо более фундаментальна. В исходном сообщении @Zihu Guo функция which вызывается дважды. Это приводит к ненужным вычислениям. Следовательно, мое добавление приведет к более быстрому коду.
- person Jacob H; 18.06.2015
@JacobH
спасибо за комментарий, вы правы. Я изменил код.
- person Zihu Guo; 18.06.2015
@JacobH Вас, ребята, может заинтересовать сравнение, которое я только что добавил (как еще один ответ).
which
работает медленно для этой задачи, потому что просматривает каждый элемент. Быстрее остановиться на первом ненулевом результате.
- person Frank; 18.06.2015
Что ж, если вас беспокоит скорость, просто используйте циклы:
x <- rpois(1e8,1)
# Zihu Guo & JacobH's answer
system.time({zeros <- which(x > 0); x[zeros[1]:tail(zeros, n = 1)]})
# user system elapsed
# 1.46 0.42 1.89
# a slightly improved version of their answer
system.time({zeros <- which(!!x); x[zeros[1]:tail(zeros, n = 1)]})
# user system elapsed
# 1.21 0.42 1.64
system.time({
lo = 0L
lov = 0L
while (!lov){ lo = lo+1L ; lov = lov+x[lo] }
hi = length(x)+1L
hiv = 0L
while (!hiv){ hi = hi-1L ; hiv = hiv+x[hi] }
x[lo:hi]
})
# user system elapsed
# 0.62 0.07 0.71
Помимо скорости, это хорошо, потому что не требует реальных знаний R. Вероятно, это можно было бы сделать быстрее с пакетом Rcpp
.
(Если весь вектор состоит из нулей, это никогда не завершится. Если это имеет значение, можно внести небольшие корректировки. Если вектор в основном нулевой, метод which
работает быстрее. Например, рассмотрим x <- rep(0L,1e8); x[1e8/2] <- 1L
.)
person
Frank
schedule
18.06.2015
хммм.. Я предполагаю, что
:
является узким местом, вероятно, seq.int
будет предпочтительнее.
- person David Arenburg; 18.06.2015
@DavidArenburg Время аналогично этому изменению в моем компе. Может быть, отрицательное индексирование лучше... давайте проверим.
- person Frank; 18.06.2015
Идея: строительство
lo:hi
может быть дороже, чем его дополнение. Для большинства семплов rpois
с лямба = 1 почти ничего не отбрасывается.
- person Frank; 18.06.2015
Отличный пример Фрэнк. Причина, по которой ваш подход быстрее, заключается в том, что обычно быстрее перебирать первые нулевые элементы вектора, чем выполнять векторизованную операцию над всем вектором. Так будет не всегда. Представьте, что у вас есть вектор длины 1e8, и первые 9e7 элементов равны нулю. Я подозреваю, что в таком сценарии подход Цзыху Го будет быстрее. Так что пусть ваши априорные предположения о вашей проблеме определяют вашу стратегию программирования.
- person Jacob H; 18.06.2015
@JacobH Да, хорошая мысль. С
x <- rep(0L,1e8); x[1e8/2] <- 1L
мой занимает целую вечность.
- person Frank; 18.06.2015