Векторизировать мышление

У меня проблема с векторизацией. Скажем, у меня есть вектор x <- c(0,0,1,0,1,1,0) , я хочу получить вектор (1,0,1,1) или удалить все 0 с первой точки до первой ненулевой точки и все 0 с последней ненулевой точки до последней точки . Обычно это легко, но сложность в том, что я не могу использовать циклы (for, while и т. д.). По сути, я должен «векторизовать» весь алгоритм. Кто-нибудь поможет, пожалуйста?


person NamelessGods    schedule 18.06.2015    source источник


Ответы (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
comment
Небольшие изменения в подходе Цзыху Го. Инициализировать вызов, к которому. то есть zeros=which(x > 0); x[zeros[1]:tail(zeros, n=1)] - person Jacob H; 18.06.2015
comment
Мое дополнение делает его более читабельным. Однако его важность гораздо более фундаментальна. В исходном сообщении @Zihu Guo функция which вызывается дважды. Это приводит к ненужным вычислениям. Следовательно, мое добавление приведет к более быстрому коду. - person Jacob H; 18.06.2015
comment
@JacobH спасибо за комментарий, вы правы. Я изменил код. - person Zihu Guo; 18.06.2015
comment
@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
comment
хммм.. Я предполагаю, что : является узким местом, вероятно, seq.int будет предпочтительнее. - person David Arenburg; 18.06.2015
comment
@DavidArenburg Время аналогично этому изменению в моем компе. Может быть, отрицательное индексирование лучше... давайте проверим. - person Frank; 18.06.2015
comment
Идея: строительство lo:hi может быть дороже, чем его дополнение. Для большинства семплов rpois с лямба = 1 почти ничего не отбрасывается. - person Frank; 18.06.2015
comment
Отличный пример Фрэнк. Причина, по которой ваш подход быстрее, заключается в том, что обычно быстрее перебирать первые нулевые элементы вектора, чем выполнять векторизованную операцию над всем вектором. Так будет не всегда. Представьте, что у вас есть вектор длины 1e8, и первые 9e7 элементов равны нулю. Я подозреваю, что в таком сценарии подход Цзыху Го будет быстрее. Так что пусть ваши априорные предположения о вашей проблеме определяют вашу стратегию программирования. - person Jacob H; 18.06.2015
comment
@JacobH Да, хорошая мысль. С x <- rep(0L,1e8); x[1e8/2] <- 1L мой занимает целую вечность. - person Frank; 18.06.2015