Заменить последовательность восхождений на среднее - PullRequest
0 голосов
/ 07 февраля 2020

У меня есть случайный список, подобный этому

X = [0, 1, 5, 6, 7, 10, 15]

, и мне нужно найти и заменить каждую последовательность восхождений на ее среднее значение. В конце это должно выглядеть так:

X = [0, 6, 10, 15]       #the 0 and 1 to 0; and the 5,6,7 to 6

Я пытался найти последовательность, вычитая второе значение из первого, вот так:

y = 0
z = []
while X[y +1] -X[y] == 1: 
            z.append(X[y])

            y = y +1

И теперь я не знаю, как например удалить 5,6 и 7 и заменить его на среднее 6.

Ответы [ 4 ]

3 голосов
/ 07 февраля 2020

Вы можете использовать itertools.groupby в списке с ключевой функцией, которая возвращает разницу каждого элемента с инкрементным счетчиком:

from itertools import groupby, count
from statistics import mean

X = [0, 1, 5, 6, 7, 10, 15]
c = count()
X = [int(mean(g)) for _, g in groupby(X, key=lambda i: i - next(c))]

X становится:

[0, 6, 10, 15]
1 голос
/ 07 февраля 2020

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

>>> res = [[x[0]]]
>>> for i in range(1, len(x)):
...     if x[i] == x[i-1] + 1:
...             res[-1].append(x[i])
...     else:
...             res.append([x[i]]
>>> res
[[0, 1], [5, 6, 7], [10], [15]]
>>> [int(sum(l)/len(l)) for l in res]
[0, 6, 10, 15]
0 голосов
/ 07 февраля 2020

Не совсем, чтобы ответить на вопрос, который является довольно основным c CS 101 вопросом, который люди должны попытаться выяснить сами, но что я заметил относительно хорошего ответа @blhsing, так это то, что он выглядел довольно медленно. Я обнаружил, что mean() невероятно медленно!

from itertools import groupby, count
from statistics import mean
from timeit import timeit


def generate_1step_seq1(xs):
    result = []
    n = 0
    while n < len(xs):
        # sequences with step of 1 only
        if not result or xs[n] == result[-1] + 1:
            result += [xs[n]]
        else:
            # int result, rounding down
            yield sum(result) // len(result)
            result = [xs[n]]
        n += 1
    if result:
        yield sum(result) // len(result)


def generate_1step_seq2(xs):
    c = count()
    return [int(sum(xs) // len(xs)) for xs in [list(g) for _, g in groupby(xs, key=lambda i: i - next(c))]]


def generate_1step_seq3(xs):
    c = count()
    return [int(mean(g)) for _, g in groupby(xs, key=lambda i: i - next(c))]


values = [0, 1, 5, 6, 7, 10, 15]

print(list(generate_1step_seq1(values)))
print(generate_1step_seq2(values))
print(generate_1step_seq3(values))

print(timeit(lambda: list(generate_1step_seq1(values)), number=10000))
print(timeit(lambda: list(generate_1step_seq2(values)), number=10000))
print(timeit(lambda: list(generate_1step_seq3(values)), number=10000))

Изначально я подумал, что это, вероятно, связано с небольшим размером списка, но даже для больших списков, mean() ужасно медленно. Кто-нибудь случайно знает почему? Похоже, из-за очень безопасного характера statistics _sum, пытаясь избежать float ошибок округления?

0 голосов
/ 07 февраля 2020

Вот начальный прием: создайте новый список, в котором будет разница смежных элементов в списке:

diff = [X[i] - X[i-1] for i in range(1, len(X)) ]

Есть и другие способы Pythoni 1029 *, но я хочу сделать уверен, что это доступно для новых программистов.

Теперь у вас есть diff как

[1, 4, 1, 1, 3, 5]

Если у вас есть 1 в diff, у вас есть пара восхождений в X. Выполните итерацию по diff, чтобы найти последовательность значений 1. Где вы найдете это, возьмите slice из X, что соответствует значениям 1. Средний элемент этого среза - это ваше среднее значение.

Если значение не 1, тогда вы просто берете соответствующий элемент X, как вы это делали.

append обозначенные значения до z, и есть желаемый результат.

Можете ли вы взять его оттуда?

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