Накопительная сумма только для положительных чисел

r

2556 просмотра

9 ответа

695 Репутация автора

У меня есть этот вектор:

x = c(1,1,1,1,1,0,1,0,0,0,1,1)

И я хочу сделать накопительную сумму только для положительных чисел. У меня должен быть следующий вектор взамен:

xc = (1,2,3,4,5,0,1,0,0,0,1,2)

Как я мог это сделать?

Я пытался: cumsum(x)но это сделать накопительную сумму для всех значений и дает:

cumsum(x)
[1] 1 2 3 4 5 5 6 6 6 6 7 8
Автор: Math Источник Размещён: 03.02.2015 09:50

Ответы (9)


3 плюса

114 Репутация автора

Я не знаю много о R, но я написал небольшой код на Python. Логика остается неизменной на всех языках. Надеюсь, что это поможет вам

x=[1,1,1,1,1,0,1,0,0,0,1,1]
tot=0
for i in range(0,len(x)):
    if x[i]!=0:
        tot=tot+x[i]
        x[i]=tot
    else:
        tot=0
print x
Автор: Abhilash Cherukat Размещён: 03.02.2015 09:56

30 плюса

482778 Репутация автора

Решение

Один вариант

x1 <- inverse.rle(within.list(rle(x), values[!!values] <- 
                  (cumsum(values))[!!values]))
x[x1!=0] <- ave(x[x1!=0], x1[x1!=0], FUN=seq_along)
x
#[1] 1 2 3 4 5 0 1 0 0 0 1 2

Или однострочный код будет

 x[x>0] <-  with(rle(x), sequence(lengths[!!values]))
 x
 #[1] 1 2 3 4 5 0 1 0 0 0 1 2
Автор: akrun Размещён: 03.02.2015 09:58

5 плюса

43568 Репутация автора

x=c(1,1,1,1,1,0,1,0,0,0,1,1)
cumsum_ <- function(x) {
  r <- rle(x)
  s <- split(x, rep(seq_along(r$values), rle(x)$lengths))
  return(unlist(sapply(s, cumsum), use.names = F))
}
(xc <- cumsum_(x))
# [1] 1 2 3 4 5 0 1 0 0 0 1 2
Автор: lukeA Размещён: 03.02.2015 10:00

19 плюса

81260 Репутация автора

Вот возможное решение с использованием data.tablev> = 1.9.5 и его новой rleidфункции

library(data.table)
as.data.table(x)[, cumsum(x), rleid(x)]$V1
## [1] 1 2 3 4 5 0 1 0 0 0 1 2
Автор: David Arenburg Размещён: 03.02.2015 10:00

10 плюса

24082 Репутация автора

Базовое R, однолинейное решение с Map Reduce:

> Reduce('c', Map(function(u,v) if(v==0) rep(0,u) else 1:u, rle(x)$lengths, rle(x)$values))
 [1] 1 2 3 4 5 0 1 0 0 0 1 2

Или же:

unlist(Map(function(u,v) if(v==0) rep(0,u) else 1:u, rle(x)$lengths, rle(x)$values))
Автор: Colonel Beauvel Размещён: 03.02.2015 10:15

2 плюса

29 Репутация автора

x<-c(1,1,1,1,1,0,1,0,0,0,1,1)

skumulowana<-function(x) {
  dl<-length(x)
  xx<-numeric(dl+1)
  for (i in 1:dl){
    ifelse (x[i]==0,xx[i+1]<-0,xx[i+1]<-xx[i]+x[i])
  }
wynik<<-xx[1:dl+1]
return (wynik)
}

skumulowana(x)
## [1] 1 2 3 4 5 0 1 0 0 0 1 2
Автор: Wojtek Obłąk Размещён: 03.02.2015 11:21

1 плюс

4870 Репутация автора

сплит и лапы версия:

x <- c(1,1,1,1,1,0,1,0,0,0,1,1)
unlist(lapply(split(x, cumsum(x==0)), cumsum))

шаг за шагом:

a <- split(x, cumsum(x==0)) # divides x into pieces where each 0 starts a new piece
b <- lapply(a, cumsum)  # calculates cumsum in each piece
unlist(b)  # rejoins the pieces 

Результат имеет бесполезные имена, но в остальном это то, что вы хотели:

# 01 02 03 04 05 11 12  2  3 41 42 43 
#  1  2  3  4  5  0  1  0  0  0  1  2 
Автор: lebatsnok Размещён: 07.04.2016 07:34

0 плюса

9498 Репутация автора

Вот еще одно базовое решение R с использованием aggregate. Идея состоит в том, чтобы создать фрейм данных с xновым столбцом, x.1по которому мы можем применять aggregateфункции ( cumsumв данном случае):

x <- c(1,1,1,1,1,0,1,0,0,0,1,1)
r <- rle(x)
df <- data.frame(x, 
x.1=unlist(sapply(1:length(r$lengths), function(i) rep(i, r$lengths[i]))))

# df

   # x x.1
# 1  1   1
# 2  1   1
# 3  1   1
# 4  1   1
# 5  1   1
# 6  0   2
# 7  1   3
# 8  0   4
# 9  0   4
# 10 0   4
# 11 1   5
# 12 1   5

agg <- aggregate(df$x~df$x.1, df, cumsum)
as.vector(unlist(agg$`df$x`))

# [1] 1 2 3 4 5 0 1 0 0 0 1 2
Автор: 989 Размещён: 26.06.2016 09:26

2 плюса

1599 Репутация автора

Попробуйте эту однострочную ...

Reduce(function(x,y) (x+y)*(y!=0), x, accumulate=T)
Автор: sirallen Размещён: 29.11.2016 04:19
Вопросы из категории :
32x32