Eu quero escrever um código para contar e somar qualquer série de números positivos e negativos.
Os números são positivos ou negativos (sem zero).
Eu escrevi códigos com for
loops. Existe alguma alternativa criativa?
Dados
R
set.seed(100)
x <- round(rnorm(20, sd = 0.02), 3)
Pitão
x = [-0.01, 0.003, -0.002, 0.018, 0.002, 0.006, -0.012, 0.014, -0.017, -0.007,
0.002, 0.002, -0.004, 0.015, 0.002, -0.001, -0.008, 0.01, -0.018, 0.046]
rotações
R
sign_indicator <- ifelse(x > 0, 1,-1)
number_of_sequence <- rep(NA, 20)
n <- 1
for (i in 2:20) {
if (sign_indicator[i] == sign_indicator[i - 1]) {
n <- n + 1
} else{
n <- 1
}
number_of_sequence[i] <- n
}
number_of_sequence[1] <- 1
#############################
summation <- rep(NA, 20)
for (i in 1:20) {
summation[i] <- sum(x[i:(i + 1 - number_of_sequence[i])])
}
Pitão
sign_indicator = [1 if i > 0 else -1 for i in X]
number_of_sequence = [1]
N = 1
for i in range(1, len(sign_indicator)):
if sign_indicator[i] == sign_indicator[i - 1]:
N += 1
else:
N = 1
number_of_sequence.append(N)
#############################
summation = []
for i in range(len(X)):
if number_of_sequence[i] == 1:
summation.append(X[i])
else:
summation.append(sum(X[(i + 1 - number_of_sequence[i]):(i + 1)]))
resultado
x n_of_sequence sum
1 -0.010 1 -0.010
2 0.003 1 0.003
3 -0.002 1 -0.002
4 0.018 1 0.018
5 0.002 2 0.020
6 0.006 3 0.026
7 -0.012 1 -0.012
8 0.014 1 0.014
9 -0.017 1 -0.017
10 -0.007 2 -0.024
11 0.002 1 0.002
12 0.002 2 0.004
13 -0.004 1 -0.004
14 0.015 1 0.015
15 0.002 2 0.017
16 -0.001 1 -0.001
17 -0.008 2 -0.009
18 0.010 1 0.010
19 -0.018 1 -0.018
20 0.046 1 0.046
n_of_sequence
não é idêntico ao desejadoVocê pode calcular os comprimentos de execução de cada sinal usando
rle
debase
para e fazer algo assim.Para obter
n_of_sequence
Finalmente, para obter os somatórios das seqüências,
fonte
Aqui está uma função simples sem loop no R:
Então você pode fazer:
Criado em 2020-02-16 pelo pacote reprex (v0.3.0)
fonte
Aqui está uma
tidyverse
solução simples ...fonte
Quanto ao Python, alguém terá uma solução usando a biblioteca pandas. Enquanto isso, aqui está uma proposta simples:
Resultado:
Se você precisar de listas separadas, poderá fazer
ou, se os iteradores estiverem OK, basta
(explicação aqui )
fonte
Duas soluções preguiçosas diferentes em Python, usando o módulo itertools .
Usando itertools.groupby (e acumule)
Usando itertools.acumule com uma função de acumulação personalizada
O
initial
argumento da palavra-chave foi adicionado no Python 3.8. Nas versões anteriores, você pode usaritertools.chain
para acrescentar o princípio (0,0):A saída é como o esperado:
fonte
Eu recomendo o corredor de pacotes R para esse tipo de operações. streak_run calcula ocorrência consecutiva do mesmo valor e sum_run calcula soma na janela cujo comprimento é definido pelo
k
argumento.Aqui está a solução:
Abaixo do benchmark para comparar as soluções reais
fonte
df <- data.table(x)
é uma cópia de dados completa. Além disso, você está imprimindo os dados em alguns exemplos (que é outra cópia completa) enquanto não em outros.r = runner_streak(x); d = dt_streak(dt) ; all.equal(r, d$sum)
. Apenas verificado alguns bbuttv_streak
dá o mesmo quedt_streak
;count_and_sum
dá o mesmorunner_streak
que são diferentes dos dois anteriores.Em R, você também pode fazer:
fonte
Jogando minha [r] resposta no chapéu, otimizada para velocidade e funciona com qualquer comprimento de x (diferente das perguntas que foram codificadas no comprimento 20):
E, para comparar os tempos de execução no meu computador de trabalho atual (muito lento), aqui está a saída do meu microbenchmark usando todas as soluções R neste segmento. Sem surpresa, as soluções que tiram o máximo de cópias e conversões tendem a ser mais lentas.
-------------- EDIT -------------- Foi apontado pelo @nicola que minha solução não é a mais rápida para comprimentos maiores de x - o que deve ser bastante óbvio, pois estou continuamente fazendo cópias de vetores usando chamadas como x <- c (x, y). Eu só criei a solução mais rápida para comprimentos = 20 e apenas marquei a marca do microsseguro o mais baixo possível.
Para fazer uma comparação mais justa, editei todas as versões para gerar o código original da maneira que acredito ser mais rápida, mas agradeço comentários sobre isso. Aqui está o meu código de benchmarking completo e os resultados para o meu sistema muito lento. Congratulo-me com qualquer feedback.
Como esses resultados mostram, para outros comprimentos além dos otimizados, minha versão é lenta. Quanto maior o x, mais lento fica ridiculamente lento em tudo acima de 1000. Minha versão favorita é a da Ronak, que é apenas a segunda mais rápida no meu sistema. O GoGonzo é, de longe, o mais rápido da minha máquina nesses comprimentos mais longos.
fonte
data.table
solução da @ Ronak, a sua é uma ordem de magnitudes mais lenta para um comprimento de ~ 100000.No Python, além de definir uma classe para armazenar as variáveis de memória, você pode usar um fechamento para obter o mesmo.
Observe que isso funciona apenas para Python 3 (no Python 2, acho que você não pode modificar a variável de fechamento como esta). Coisa semelhante para somatório também.
fonte
Eu acho que um loop seria mais fácil de ler, mas apenas por diversão, aqui está uma solução em Python usando recursão:
fonte
Aqui está outra abordagem R básica:
fonte
Reduce
oculta um loop, portanto, essa não é uma solução sem loop.Uma resposta simples em python ignora o caso 0:
Uma solução um pouco mais sofisticada também cuida do caso 0:
fonte