2016-07-21 3 views
1

У меня есть некоторые данные, аналогичные ниже данныхИндексирование состояние с R

 Time output 
     2  1 
     2  1 
     2  2 
     2  2 
     2  1 
     2  2 
     2  1 

Мне нужно добавить две колонки в этих данных:

  • index: всякий раз, когда output==2 он должен сосчитать и подсчета остатков так же, пока он не встретится с 1 сейчас, если он встретит другой 2, он должен увеличить его количество.
  • total time: Необходимо просуммировать время, когда output==2 между 1.

Ожидаемый результат:

 Time output index total_time 
     2  1  0   0 
     2  1  0   0 
     2  2  1   4 
     2  2  1   4 
     2  1  0   0 
     2  2  2   2 
     2  1  0   0 

Спасибо заранее.

ответ

2

здесь решение на основе rle и cumsum. Я добавляю комментарии, чтобы объяснить основные шаги, даже очень сложно объяснить это словами. Решение векторизовано без какого-либо цикла.

## init the vectors results with zeros 
dx$index <- rep(0,nrow(dx)) 
dx$total_time <- rep(0,nrow(dx)) 
## use rle to get the position/length 
rr <- rle(dx$output) 
## only the val 2 is important for us , so we store into index 
ii <- rr$values==2 
## we replace the occuronce of 2 in the original vector by the cumulative 
## repeating it : hard to explain !! 
vals <- cumsum(ii)[ii] 
occurs <- rr$len[ii] 
dx$index[dx$output==2] <- rep(vals,occurs) 
## same thing for the total just we change the value here 
dx$total_time[dx$output==2] <- rep(occurs*2,occurs) 

#  Time output index  total_time 
# 1 2  1  0   0 
# 2 2  1  0   0 
# 3 2  2  1   4 
# 4 2  2  1   4 
# 5 2  1  0   0 
# 6 2  2  2   2 
# 7 2  1  0   0 

где ах читается как:

dx <- read.table(text=" Time output 
     2  1 
      2  1 
      2  2 
      2  2 
      2  1 
      2  2 
      2  1",header=T) 
+0

спасибо это работает !! – amy

2

Используя некоторую индексацию и начинку о:

dat[c("index","total_time")] <- 0 
hit <- dat$output==2 
dat$index[hit] <- c(factor(cumsum(!hit)[hit])) 
dat$total_time[hit] <- with(dat[hit,], ave(output, index, FUN=sum)) 

# Time output index total_time 
#1 2  1  0   0 
#2 2  1  0   0 
#3 2  2  1   4 
#4 2  2  1   4 
#5 2  1  0   0 
#6 2  2  2   2 
#7 2  1  0   0 
+0

спасибо, что это работает !! – amy

+0

это намного проще, чем принятое решение. – agstudy

+0

@agstudy - ваш заметно быстрее (с 1M + строками, например) – thelatemail

1

Вот вариант использования data.table. Преобразуйте 'data.frame' в 'data.table' (setDT(df1)), создайте 'index' с помощью rleid по логическому вектору (output == 2), когда 'index' не равен 0, присвойте 'index' как match между элементами в «индексе» и unique значений, создать «Total_time», сгруппированный по «индексу», где «индекс» не 0, если необходимо NA элементов могут быть преобразованы в 0.

library(data.table) 
setDT(df1)[, index:= rleid(output ==2)*(output ==2) 
      ][index!=0, index := match(index, unique(index)) 
      ][index!=0, total_time :=sum(Time) , index 
      ][is.na(total_time), total_time := 0] 
df1 
# Time output index total_time 
#1: 2  1  0   0 
#2: 2  1  0   0 
#3: 2  2  1   4 
#4: 2  2  1   4 
#5: 2  1  0   0 
#6: 2  2  2   2 
#7: 2  1  0   0 
Смежные вопросы