У меня есть два списка Python разной длины. Можно предположить, что один из списков во много раз больше другого.

Оба списка содержат одни и те же физические данные, но получены с разными частотами выборки.

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

Я придумал следующий код, который в основном выполняет свою работу, но он не очень Pythonic и не способен обрабатывать очень большие списки быстрым способом:

import math

a = [1,2,3,4,5,6,7,8,9,10]
b = [1,4.5,6.9]

if len(a) > len(b):
    div = int(math.floor(len(a)/len(b)))
    a = a[::div]
    diff = len(a)-len(b)
    a = a[:-diff]
else:
    div = int(math.floor(len(b)/len(a)))
    b = b[::div]
    diff = len(b)-len(a)
    b = b[:-diff]
print a
print b

Я был бы признателен, если бы более опытные пользователи Python могли разработать альтернативные способы решения этой задачи.

Любой ответ или комментарий высоко ценится.

4
Rickson 30 Авг 2017 в 19:23

4 ответа

Лучший ответ

Вот сокращенная версия кода (не обязательно лучшая производительность):

a = [1,2,3,4,5,6,7,8,9,10]
b = [1,4.5,6.9]
order = 0  # To determine a and b.

if len(b) > len(a):
    a, b = b, a  # swap the values so that 'a' is always larger.
    order = 1

div = len(a) / len(b)  # In Python2, this already gives the floor.
a = a[::div][:len(b)]

if order:
    print b
    print a
else:
    print a
    print b

Поскольку в конечном итоге вы отбрасываете некоторые из последних элементов большого списка, явный цикл for может повысить производительность, так как тогда вам не нужно «переходить» к значениям, которые будут отбрасываться:

new_a = []
jump = len(b)
index = 0
for i in range(jump):
    new_a.append(a[index])
    index += jump
a = new_a
1
Sam Chats 1 Сен 2017 в 10:51
#a = [1,2,3,4,5,6,7,8,9,10]
#b = [1,4.5,6.9]

a, b = zip(*zip(a, b))

# a = [1, 2, 3]
# b = [1, 4.5, 6.9]

Внутренний почтовый индекс объединяет списки в пар, отбрасывая лишние элементы из большого списка, возвращая что-то вроде [(1, 1), (2, 4.5), (3, 6.9)]. Затем внешний zip выполняет обратное (поскольку мы распаковываем с помощью оператора *), но поскольку мы отбросили излишки при первом zip, списки должны быть одинакового размера. Возвращается как [a, b], поэтому мы распаковываем соответствующие переменные (a, b = ...).

Увидеть https://www.programiz.com/python-programming/methods/ встроенный / zip для получения дополнительной информации о zip и использования его в качестве собственного обратного

-1
Ibraheem Rodrigues 30 Авг 2017 в 16:44

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

import numpy as np
a = np.array(a)
b = np.array(b)

Индексация такая же. Можно использовать len для массивов, но array.shape является более общим, давая следующий (очень похожий) код.

 a[::a.shape[0] // b.shape[0]]

С точки зрения производительности это должно значительно повысить скорость работы с большинством данных. Тестирование с гораздо большими массивами a и b (10e6 и 1e6 элементов соответственно) показывает, что numpy может дать значительное увеличение производительности.

a = np.ones(10000000)
b = np.ones(1000000)

%timeit a[::a.shape[0] // b.shape[0]]  # Numpy arrays
1000000 loops, best of 3: 348 ns per loop

a = list(a); 
b = list(b);
%timeit a[::len(a) // len(b)]    # Plain old python lists
1000000 loops, best of 3: 29.5 ms per loop
1
user2699 30 Авг 2017 в 17:24

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

from __future__ import division

a = [1,2,3,4,5,6,7,8,9,10]
b = [1,4.5,6.9]

def zip_downsample(a, b):
    if len(a) > len(b):
        b, a = a, b  # make b the longer list
    for i in xrange(len(a)):
        yield a[i], b[i * len(b) // len(a)]

for z in zip_downsample(a, b):
    print z
0
c2huc2hu 30 Авг 2017 в 16:32