2016-02-11 2 views
4

Я имею выглядя данные, как следующее:Экстрагирования чередование из вектора R

A= c(0,0,0,-1,0,0,0,1,1,1,0,0,-1,0,0,-1,-1,1,1,1,-1,0,0,0,-1,0,0,-1,-1,1,1,0,0,0,0,1,-1) 

Цель состоит в том, чтобы извлечь чередующиеся -1S и 1s. Я хочу создать функцию, в которой входной вектор содержит 0,1 и -1. Выход идеально выделяет все 0s и чередует -1s и 1s.

Например, требуемый выход для приведенного выше примера:

B= c(0,0,0,-1,0,0,0,1,0,0,0,0,-1,0,0,0,0,1,0,0,-1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,-1) 

Два 1s в 9-м и 10-м месте в А оказалось равным 0, потому что мы только сохранить первое 1 или -1 появляться. По этой причине -1s в 16-м и 17-м местоположениях A также поворачиваются на 0.

У кого-нибудь есть хорошая идея для создания такой функции?

+1

Почему этот вопрос обсуждается и vtc? Это хорошо объяснено на примере. –

+0

Я не уверен. – jay2020

+0

Нечетным значением, которое мне кажется, является позиция 16. Он переключается с «0» в позиции 15 на «-1», но удаляется. Зачем? –

ответ

5

Определение позиций ненулевых значений:

w = which(A != 0) 

Для каждого прогона аналогичных значений, в A[w], занимать позицию первый:

library(data.table) 
wkeep = tapply(w, rleid(A[w]), FUN = function(x) x[1]) 

Установить все остальные значения до нуля:

# following @alexis_laz's approach 
B = numeric(length(A)) 
B[ wkeep ] = A[ wkeep ] 

Таким образом, вам не нужно делать сравнения в цикле, в котором R медленнее, я думаю.


rleid происходит из данных.table. С базой R, вы можете сделать wkeep с предложением @ alexis_laz в:

wkeep = w[c(TRUE, A[w][-1L] != A[w][-length(w)])] 

Или написать свой собственный rleid, как и в Josh's answer.

+2

На одном и том же подходе: w = which (A! = 0L); wkeep = w [c (TRUE, A [w] [- 1L]! = A [w] [- length (w)])]; ans = числовое (длина (A)); ans [wkeep] = A [wkeep]; ans' –

+1

@alexis_laz Существующий ответ отличный.Но я бы сказал, что ваш достаточно разный, чтобы его можно было публиковать самостоятельно, тем более, что он использует только базовые функции R (мне было легче понять). – TooTone

+0

Спасибо @alexis_laz. Я добавил ваш подход к 'wkeep' и перезаписал свой третий шаг вашим (для создания' ans'). – Frank

2

Вы должны сдвинуть весь массив и переменную флага, которую вы проверяете, если ранее вы обнаружили 1 или -1. это может быть возможным псевдокод алгоритма:

while i < length(a): 

    if flag == 1 && a[i]=-1: 
     b[i]=a[i]; 
     flag = -1; 
    else if flag == -1 && a[i] = 1: 
     b[i]=a[i]; 
     flag = 1; 
    else: 
     b[i]=0; 
    i++; 
}//end of while 
+0

Спасибо за совет – jay2020

3

Это действительно просто Конкретизация псевдо-кода GWarius в. (Я уже имел структуру, но логик, которая была неисправной.)

last1 <- -A[which(A != 0)[1] ] # The opposite of the first non-zero item 
for (i in seq_along(A)){ 
      if(last1==1 && A[i]==-1 ){ last1 <- -1 
      } else {if (last1 == -1 && A[i] == 1) { last1 <- 1 
       } else {A[i] <- 0}} } 
A 
[1] 0 0 0 -1 0 0 0 1 0 0 0 0 -1 0 0 0 0 1 0 0 -1 0 0 
[24] 0 0 0 0 0 0 1 0 0 0 0 0 0 -1 

> identical(A, B) 
[1] TRUE 
+1

Да. Я пробовал с last1 = 0, и это не удалось. Я думаю, вы могли бы установить его как -A [который (A! = 0) [1]] ' –

+0

Спасибо. Я уже решил это с помощью предложения Warlus, поэтому мне пришлось выбирать Warlus. Но я очень ценю ваше время. – jay2020

+0

Нет проблем. Я потратил больше времени на некоторые вопросы и получил меньше очков. –