Je veux écrire un code pour compter et additionner toute série de nombres positifs et négatifs.
Les nombres sont positifs ou négatifs (pas de zéro).
J'ai écrit des codes avec des for
boucles. Existe-t-il une alternative créative?
Les données
R
set.seed(100)
x <- round(rnorm(20, sd = 0.02), 3)
python
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]
boucles
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])])
}
python
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)]))
résultat
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'est pas identique à celle souhaitéeVous pouvez calculer les longueurs de chaque signe en utilisant
rle
debase
à et faire quelque chose comme ça.Obtenir
n_of_sequence
Enfin, pour obtenir les sommations des séquences,
la source
Voici une fonction simple sans boucle dans R:
Vous pouvez donc faire:
Créé le 2020-02-16 par le package reprex (v0.3.0)
la source
Voici une
tidyverse
solution simple ...la source
Quant à Python, quelqu'un trouvera une solution en utilisant la bibliothèque pandas. En attendant, voici une proposition simple:
Production:
Si vous avez besoin de listes séparées, vous pouvez le faire
ou, si les itérateurs sont OK, simplement
(explication ici )
la source
Deux solutions paresseuses différentes en Python, utilisant le module itertools .
Utiliser itertools.groupby (et accumuler)
Utilisation d'itertools.accumulate avec une fonction d'accumulation personnalisée
L'
initial
argument mot-clé a été ajouté dans Python 3.8. Dans les versions antérieures, vous pouvez utiliseritertools.chain
pour ajouter le tuple (0,0):Le résultat est comme prévu:
la source
Je recommande le runner du package R pour ce type d'opérations. streak_run calcule l'occurrence consécutive de la même valeur et sum_run calcule la somme dans la fenêtre dont la longueur est définie par un
k
argument.Voici la solution:
Ci-dessous le repère pour comparer les solutions réelles
la source
df <- data.table(x)
une copie complète des données. En outre, vous imprimez les données dans certains exemples (qui sont une autre copie complète), mais pas dans d'autres.r = runner_streak(x); d = dt_streak(dt) ; all.equal(r, d$sum)
. Seulement vérifié quelques b maistv_streak
donne le même quedt_streak
;count_and_sum
donne les mêmes que ceuxrunner_streak
qui sont différents des deux précédents.Dans R, vous pouvez également faire:
la source
Lancer ma [r] réponse dans le chapeau, optimisé pour la vitesse et fonctionne avec n'importe quelle longueur de x (contrairement au demandeur qui était codé en dur pour la longueur 20):
Et, pour comparer les temps d'exécution sur mon ordinateur de travail actuel (très lent), voici la sortie de mon microbenchmark en utilisant toutes les solutions R de ce fil. Sans surprise, les solutions réalisant le plus de copies et de conversions étaient généralement plus lentes.
-------------- EDIT -------------- Il a été souligné par @nicola que ma solution n'est pas la plus rapide pour des longueurs de x plus longues - qui devrait être assez évident car je fais continuellement des copies de vecteurs en utilisant des appels comme x <- c (x, y). Je n'ai créé que la solution la plus rapide pour des longueurs = 20 et je n'ai fait que des microparamètres aussi bas que possible pour cela.
Pour faire une comparaison plus juste, j'ai édité toutes les versions pour générer le code original de la manière que je pense serait la plus rapide, mais j'accueille favorablement les commentaires à ce sujet. Voici mon code complet d'analyse comparative et les résultats pour mon système très lent. Je me réjouis de toute rétroaction.
Comme ces résultats le montrent, pour d'autres longueurs que celles pour lesquelles j'ai optimisé, ma version est lente. Plus le x est long, plus il se met à ralentir ridiculement pour tout ce qui dépasse 1000. Ma version préférée est celle de Ronak qui n'est que la deuxième plus rapide de mon système. GoGonzo est de loin le plus rapide sur ma machine à ces longueurs plus longues.
la source
data.table
solution de @ Ronak, la vôtre est d'un ordre de grandeur plus lent pour une longueur de ~ 100000.En Python, outre la définition d'une classe pour stocker les variables de mémoire, vous pouvez utiliser une fermeture pour y parvenir.
Notez que cela ne fonctionne que pour Python 3 (en Python 2, je pense que vous ne pouvez pas modifier la variable de fermeture comme ceci). Même chose pour la sommation.
la source
Je pense qu'une boucle serait plus facile à lire, mais juste pour le plaisir, voici une solution en Python utilisant la récursivité:
la source
Voici une autre approche de base R:
la source
Reduce
cache une boucle, donc ce n'est pas une solution sans boucle.Une réponse simple en python, ignore le cas 0:
Une solution un peu plus sophistiquée, s'occupe également du cas 0:
la source