Подсчет и суммирование последовательностей положительных и отрицательных чисел - PullRequest
31 голосов
/ 13 февраля 2020

Я хочу написать код для подсчета и суммирования любых положительных и отрицательных серий чисел.
Числа либо положительные, либо отрицательные (без нуля).
Я написал коды с for циклами. Есть ли творческая альтернатива?

Данные

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]

петли

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)]))

результат

        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

Ответы [ 14 ]

2 голосов
/ 23 февраля 2020

Простой python ответ, игнорирует регистр 0:

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]

count = 0
sign_positive = x[0] > 0
sign_count = []
for n in x:
    # the idea is to keep track of the sign and increment the 
    # count if it agrees with the current number we are looking at
    if (n > 0 and sign_positive) or (n < 0 and not sign_positive):
        count = count + 1
    # if it does not, the count goes back to 1
    else:
        count = 1
    # Whether we increased the count or not, we update whether the
    # sign was positive or negative
    sign_positive = n > 0
    sign_count.append(count)

# This is just to reproduce the output 
# (although I find the last repetition of the number unnecessary)    
results = list(zip(x, sign_count))
for i, result in enumerate(results):
    print(f"{i: >2d} {result[0]: .3f} {result[1]: >2d} {result[0]: .3f}")

 0 -0.010  1 -0.010
 1  0.003  1  0.003
 2 -0.002  1 -0.002
 3  0.018  1  0.018
 4  0.002  2  0.002
 5  0.006  3  0.006
 6 -0.012  1 -0.012
 7  0.014  1  0.014
 8 -0.017  1 -0.017
 9 -0.007  2 -0.007
10  0.002  1  0.002
11  0.002  2  0.002
12 -0.004  1 -0.004
13  0.015  1  0.015
14  0.002  2  0.002
15 -0.001  1 -0.001
16 -0.008  2 -0.008
17  0.010  1  0.010
18 -0.018  1 -0.018
19  0.046  1  0.046

Немного более сложное решение, также учитывает регистр 0:

# To test the 0 case I am changing two numbers to 0
x = [-0.01, 0.003, -0.002, 0.018, 
     0.002, 0.006, -0.012, 0.014, 
    -0.017, -0.007, 0, 0, 
    -0.004, 0.015, 0.002, -0.001, 
    -0.008, 0.01, -0.018, 0.046]

# The rest is similar
count = 0
# This time we are using a nested ternary assignment 
# to account for the case of 0
# This would be more readable as a function, 
# but what it does is simple
# It returns None if n is 0, 
# True if it is larger than 0 
# and False if it less than 0
sign_positive = None if n == 0 else False if n < 0 else True
sign_count = []
for n in x:
    # We add the case of 0 by adding a third condition where
    # sign_positive was None (meaning the previous
    # number was 0) and the current number is 0.
    if (n > 0 and sign_positive) or \
       (n < 0 and not sign_positive) or \
       (n == 0 and sign_positive == None):
        count = count + 1
    else:
        count = 1
    sign_positive = None if n == 0 else False if n < 0 else True
    sign_count.append(count)
results = list(zip(x, sign_count))
for i, result in enumerate(results):
    print(f"{i: >2d} {result[0]: .3f} {result[1]: >2d} {result[0]: .3f}")

 0 -0.010  1 -0.010
 1  0.003  1  0.003
 2 -0.002  1 -0.002
 3  0.018  1  0.018
 4  0.002  2  0.002
 5  0.006  3  0.006
 6 -0.012  1 -0.012
 7  0.014  1  0.014
 8 -0.017  1 -0.017
 9 -0.007  2 -0.007
10  0.000  1  0.000
11  0.000  2  0.000
12 -0.004  3 -0.004
13  0.015  1  0.015
14  0.002  2  0.002
15 -0.001  1 -0.001
16 -0.008  2 -0.008
17  0.010  1  0.010
18 -0.018  1 -0.018
19  0.046  1  0.046
2 голосов
/ 21 февраля 2020

Я думаю, что все oop будет легче читать, но просто для удовольствия, вот решение в 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]


def sign(number):
    return 1 if number > 0 else -1


def sum_previous(pos, result=None):
    if not result:
        result = x[pos]
    else:
        result += x[pos]
    if pos == 0 or sign(x[pos]) != sign(x[pos-1]):
        return result
    else:
        return sum_previous(pos-1, result)


results = [sum_previous(i) for i in range(len(x))]
print(results)
2 голосов
/ 21 февраля 2020

Вот еще один базовый подход R:

data.frame(x,
           n = sequence(rle(sign(x))$lengths),
           sum = Reduce(function(x, y) if (sign(x) == sign(y)) x + y else y, x, accumulate = TRUE))

        x n    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
2 голосов
/ 17 февраля 2020

В Python, кроме определения класса для хранения переменных памяти, вы можете использовать замыкание для достижения того же.

def run():
    count = 0
    last_sign = 0

    def sign(i):
        return 1 if i > 0 else -1

    def f(i):
        nonlocal count
        nonlocal last_sign
        if sign(i) == last_sign:
            count = count+1
        else:
            last_sign = sign(i)
            count = 1
        return count

    return f

f = run()
y = [f(i) for i in x]

Обратите внимание, что это работает только для Python 3 (в Python 2 Я думаю, что вы не можете изменить переменную замыкания следующим образом). Аналогичная вещь для суммирования.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...