Quiero escribir un código para contar y sumar cualquier serie de números positivos y negativos.
Los números son positivos o negativos (sin cero).
He escrito códigos con for
bucles. ¿Hay alguna alternativa creativa?
Datos
R
set.seed(100)
x <- round(rnorm(20, sd = 0.02), 3)
pitón
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]
bucles
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ón
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
no es idéntico al deseadoPuede calcular las longitudes de ejecución de cada signo usando
rle
frombase
y hacer algo como esto.Llegar
n_of_sequence
Finalmente, para obtener las sumas de las secuencias,
fuente
Aquí hay una función simple sin bucle en R:
Entonces puedes hacer:
Creado el 16/02/2020 por el paquete reprex (v0.3.0)
fuente
Aquí hay una
tidyverse
solución simple ...fuente
En cuanto a Python, alguien encontrará una solución usando la biblioteca de pandas. Mientras tanto, aquí hay una propuesta simple:
Salida:
Si necesita listas separadas, puede hacer
o, si los iteradores están bien, simplemente
(explicación aquí )
fuente
Dos soluciones perezosas diferentes en Python, utilizando el módulo itertools .
Usando itertools.groupby (y acumular)
Usando itertools.accumulate con una función de acumulación personalizada
El
initial
argumento de la palabra clave se agregó en Python 3.8. En versiones anteriores, puede usaritertools.chain
para anteponer la tupla (0,0):El resultado es el esperado:
fuente
Recomiendo R package runner para este tipo de operaciones. streak_run calcula la ocurrencia consecutiva del mismo valor, y sum_run calcula la suma en la ventana cuya longitud se define por
k
argumento.Aquí hay solución:
Por debajo del punto de referencia para comparar soluciones reales
fuente
df <- data.table(x)
es una copia de datos completa. Además, está imprimiendo los datos en algunos ejemplos (que es otra copia completa) mientras no en otros.r = runner_streak(x); d = dt_streak(dt) ; all.equal(r, d$sum)
. Sólo comprobado unos pocos bbuttv_streak
da lo mismo quedt_streak
;count_and_sum
da lo mismorunner_streak
que son diferentes de los dos anteriores.En R, también puedes hacer:
fuente
Lanzando mi [r] respuesta en el sombrero, optimizado para la velocidad y funciona con cualquier longitud de x (a diferencia del autor de la pregunta que estaba codificado para la longitud 20):
Y, para comparar los tiempos de ejecución en mi computadora de trabajo actual (muy lenta), aquí está el resultado de mi microbenchmark usando todas las soluciones R en este hilo. Como era de esperar, las soluciones que hacen la mayor cantidad de copias y conversiones tienden a ser más lentas.
-------------- EDITAR -------------- @nicola señaló que mi solución no es la más rápida para longitudes más largas de x, que debería ser bastante obvio ya que continuamente estoy haciendo copias de vectores usando llamadas como x <- c (x, y). Solo creé la solución más rápida para longitudes = 20 y solo microbenchmarked tan bajo como pude para eso.
Para hacer una comparación más justa, edité todas las versiones para generar el código original de la manera que creo que sería más rápida, pero agradezco sus comentarios al respecto. Aquí está mi código de evaluación comparativa completo y los resultados para mi sistema muy lento. Agradezco cualquier comentario.
Como muestran estos resultados, para otras longitudes de las que optimicé, mi versión es lenta. Cuanto más larga es x, más lenta se vuelve a ridículamente lenta en todo por encima de 1000. Mi versión favorita es la de Ronak, que es la segunda más rápida en mi sistema. GoGonzo es el más rápido en mi máquina con diferencia en estas longitudes más largas.
fuente
data.table
solución de @ Ronak, la suya es un orden de magnitudes más lento para una longitud de ~ 100000.En Python, además de definir una clase para almacenar las variables de memoria, puede usar un cierre para lograr lo mismo.
Tenga en cuenta que esto funciona solo para Python 3 (en Python 2, creo que no puede modificar la variable de cierre de esta manera). Algo similar para la suma también.
fuente
Creo que un bucle sería más fácil de leer, pero solo por diversión, aquí hay una solución en Python usando la recursividad:
fuente
Aquí hay otro enfoque base R:
fuente
Reduce
oculta un bucle, por lo que esta no es una solución sin bucle.Una respuesta simple de Python, ignora el caso 0:
Una solución un poco más sofisticada, también se ocupa del caso 0:
fuente