【问题标题】:Match length of two Python lists两个 Python 列表的匹配长度
【发布时间】:2018-02-08 11:09:32
【问题描述】:

我有两个不同长度的 Python 列表。人们可能会假设其中一个列表比另一个大几倍。

两个列表包含相同的物理数据,但以不同的采样率捕获。

我的目标是对较大信号进行下采样,使其具有与较小信号完全相同的数据点。

我想出了以下代码,它基本上可以完成这项工作,但既不是 Python 风格,也不能以高性能的方式处理非常大的列表:

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 用户能详细说明解决此任务的替代方法,我将不胜感激。

非常感谢任何答案或评论。

【问题讨论】:

  • 请注意,仅推进除法的地板可能会导致较长列表的较大累积错误!例如,如果一个列表有 7 个元素,而另一个有 4 个元素,则您将只取前四个元素,而不是其他所有元素。
  • @tobias_k 是的。然而,就我而言,一个列表可能有 80000 个元素,而另一个列表可能只有 300 个。

标签: python python-2.7 list numpy signal-processing


【解决方案1】:

这是代码的缩短版本(不一定性能更好):

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

【讨论】:

  • 您可以进一步简化为a = a[::div][:len(b)]。如果我们从头开始计算,则不需要 a 的新长度。恕我直言,它的意图也更清楚了。
  • @tobias_k 谢谢!我已经添加了它。你觉得我的其他代码怎么样?
  • 但是,请注意,OP 的原始代码不会交换变量... 可能需要修改下一行的代码,或者您应该再次交换。
  • @tobias_k 请原谅?我不明白。
  • @SamChats 是的,我建议删除交换。您也可以使用 numpy 数组而不是 user2699 提到的列表。感谢您的努力!
【解决方案2】:

首先,为了提高性能,您应该使用numpy。这些问题被标记为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

【讨论】:

    【解决方案3】:

    如果您要遍历列表,则可以使用生成器,这样您就不必将整个内容复制到内存中。

    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
    

    【讨论】:

      【解决方案4】:
      #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]
      

      内部 zip 将列表组合成 par,从较大的列表中丢弃多余的项目,返回类似 [(1, 1), (2, 4.5), (3, 6.9)] 的内容。然后外部 zip 执行与此相反的操作(因为我们使用 * 运算符解包),但是由于我们已经丢弃了第一个 zip 中的多余部分,因此列表应该是相同的大小。这将返回为[a, b],因此我们随后解压缩到相应的变量(a, b = ...)。

      https://www.programiz.com/python-programming/methods/built-in/zip 了解有关 zip 的更多信息并将其用作它自己的逆向

      【讨论】:

      • a 的预期输出是[1, 4, 7],b 不需要计算
      猜你喜欢
      • 2023-01-22
      • 1970-01-01
      • 2020-03-29
      • 2022-11-16
      • 1970-01-01
      • 2012-01-02
      • 1970-01-01
      • 2013-08-19
      • 2017-11-30
      相关资源
      最近更新 更多