Chcę napisać kod zliczający i sumujący każdą dodatnią i ujemną serię liczb.
Liczby są albo dodatnie, albo ujemne (bez zera).
Napisałem kody z for
pętlami. Czy jest jakaś kreatywna alternatywa?
Dane
R
set.seed(100)
x <- round(rnorm(20, sd = 0.02), 3)
pyton
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]
pętle
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])])
}
pyton
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)]))
wynik
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
nie jest identyczny z pożądanymMożesz obliczyć długości przebiegu każdego znaku za pomocą
rle
odbase
do i zrobić coś takiego.Aby dostać
n_of_sequence
Wreszcie, aby uzyskać podsumowanie sekwencji,
źródło
Oto prosta funkcja nie zapętlająca się w R:
Możesz więc zrobić:
Utworzono 2020-02-16 przez pakiet reprezentx (v0.3.0)
źródło
Oto proste
tidyverse
rozwiązanie ...źródło
Jeśli chodzi o Python, ktoś wymyśli rozwiązanie przy użyciu biblioteki pand. Tymczasem oto prosta propozycja:
Wynik:
Jeśli potrzebujesz osobnych list, możesz to zrobić
lub, jeśli iteratory są OK, po prostu
(wyjaśnienie tutaj )
źródło
Dwa różne leniwe rozwiązania w Pythonie, wykorzystujące moduł itertools .
Korzystanie z itertools.groupby (i kumulacja)
Za pomocą itertools.accumulate z niestandardową funkcją akumulacji
initial
Argumentem kluczowe dodano w Pythonie 3.8. We wcześniejszych wersjach możesz użyć,itertools.chain
aby dodać (0,0) -pleple:Dane wyjściowe są zgodne z oczekiwaniami:
źródło
Polecam biegacz pakietu R do tego rodzaju operacji. streak_run oblicza kolejne wystąpienie tej samej wartości, a sum_run oblicza sumę w oknie, której długość jest zdefiniowana przez
k
argument.Oto rozwiązanie:
Poniżej testu porównawczego rzeczywistych rozwiązań
źródło
df <- data.table(x)
jest pełna kopia danych. Ponadto drukujesz dane w niektórych przykładach (co jest kolejną pełną kopią), a nie w innych.r = runner_streak(x); d = dt_streak(dt) ; all.equal(r, d$sum)
. Tylko zaznaczone kilka bbuttv_streak
daje to samo codt_streak
;count_and_sum
daje to samo,runner_streak
co różni się od dwóch poprzednich.W R możesz także:
źródło
Rzucanie mojej [r] odpowiedzi w czapce, zoptymalizowane pod kątem szybkości i działa z dowolną długością x (w przeciwieństwie do pytającego, który był zakodowany na stałe dla długości 20):
I, aby porównać czasy działania na moim bieżącym (bardzo wolnym) komputerze roboczym, oto wyniki mojego mikrobenchmarka wykorzystującego wszystkie rozwiązania R w tym wątku. Nic dziwnego, że rozwiązania generujące najwięcej kopii i konwersji były zwykle wolniejsze.
-------------- EDYCJA -------------- @nicola zauważył, że moje rozwiązanie nie jest najszybsze dla dłuższych długości x - co powinno być dość oczywiste, ponieważ ciągle tworzę kopie wektorów, używając wywołań takich jak x <- c (x, y). Stworzyłem tylko najszybsze rozwiązanie dla długości = 20 i po prostu oznaczyłem mikrodrukiem tak nisko, jak tylko mogłem.
Aby dokonać bardziej sprawiedliwego porównania, edytowałem wszystkie wersje, aby wygenerować oryginalny kod w sposób, który moim zdaniem byłby najszybszy, ale cieszę się z opinii na ten temat. Oto mój pełny kod testu i wyniki dla mojego bardzo wolnego systemu. Czekam na wszelkie opinie.
Jak pokazują te wyniki, dla innych długości niż te, dla których zoptymalizowałem, moja wersja jest powolna. Im dłuższe jest x, tym wolniej robi się absurdalnie wolne we wszystkim powyżej 1000. Moja ulubiona wersja to Ronak, która jest dopiero drugą najszybszą w moim systemie. GoGonzo jest najszybszy na mojej maszynie jak na te dłuższe odcinki.
źródło
data.table
@ Ronak, twoje jest o rząd wielkości wolniejsze na długości ~ 100000.W Pythonie, oprócz definiowania klasy do przechowywania zmiennych pamięci, można użyć zamknięcia, aby osiągnąć to samo.
Zauważ, że działa to tylko w Pythonie 3 (w Pythonie 2 myślę, że nie możesz zmodyfikować zmiennej zamknięcia w ten sposób). Podobnie rzecz w przypadku sumowania.
źródło
Myślę, że pętla byłaby łatwiejsza do odczytania, ale dla zabawy, oto rozwiązanie w Pythonie wykorzystujące rekurencję:
źródło
Oto inne podstawowe podejście R:
źródło
Reduce
ukrywa pętlę, więc nie jest to rozwiązanie niepętlące.Prosta odpowiedź na python, ignoruje przypadek 0:
Trochę bardziej wyrafinowane rozwiązanie, zajmuje się również przypadkiem 0:
źródło