【问题标题】:Repeat values in a column based on another基于另一列重复列中的值
【发布时间】:2019-02-01 00:05:11
【问题描述】:

假设我有一个数组(不一定是正方形)

my_array = ['name_1', 3
            'name_2', 2]

我想以length 3+2=5 的列表(或numpy 数组等)结束,其中前三个位置分配给'name_1',接下来的两个位置分配给'name_2'。因此输出将是

['name_1', 'name_1', 'name_1', 'name_2', 'name_2']

这是我到目前为止所做的;请问有更好的方法吗?

import numpy as np

my_array = np.array([['name_1', 3], ['name_2', 2]])
l = []
for i in range(my_array.shape[0]):
    x = [my_array[i, 0].tolist()] * np.int(my_array[i, 1])
    l.append(x)

flat_list = [item for sublist in l for item in sublist]
print(flat_list)

哪个打印:

['name_1', 'name_1', 'name_1', 'name_2', 'name_2']

谢谢!

【问题讨论】:

    标签: python arrays python-3.x numpy


    【解决方案1】:

    使用np.repeat:

    my_array[:,0].repeat(my_array[:,1].astype(int))
    # array(['name_1', 'name_1', 'name_1', 'name_2', 'name_2'], dtype='<U6')
    

    【讨论】:

    • 感谢大家的意见,这里有几种不同的方法,都非常有帮助。没想到真的有这么多不同的方式。不幸的是,我没有进行“赛马”来比较执行时间,但我接受了coldspeed的回答,因为它简洁、紧凑、易于理解并且对我来说也是新的;直到现在才看到 np.repeat 。特别感谢 Travis 的广泛解释,同时也感谢他有额外的时间提出两个解决方案!
    【解决方案2】:

    您可以结合使用列表乘法和sum

    sum(([my_array[i]] * my_array[i+1] for i in range(0, len(my_array), 2)), [])
    

    【讨论】:

    • 不要使用sum 以这种方式连接列表。使用itertools.chain,但即便如此,这仍然是相当过分的。
    【解决方案3】:

    我不是 numpy 专家,“更好”的方式是主观的。这是使用itertools的一种方法

    from itertools import chain, repeat
    chain.from_iterable(repeat(elem, count) for elem, count in zip(my_array[::2], my_array[1::2]))
    

    下面是它的工作原理。

    my_array[::2] 返回一个每隔一个元素组成的切片,因为第一个和第二个参数为空,它从 0 开始到结尾。这将是您的第一列的所有内容,它们是您的输入元素。您的计数在另一列中,因此我们可以使用my_array[1::2] 来获取计数。这些切片很好,因为它们不会创建数组的新副本,只是跳过所有其他元素并从某个偏移量开始的“视图”。

    现在我们要成对列举它们。使用zip() 很方便。它并行使用迭代器/生成器/序列,并为每个元素提供单独的绑定。因此,当我们在 for 构造中进行压缩时,我们将每个元素绑定到 elem,并将每个计数绑定到 count

    for in 构造允许我们为每对参数提供一个转换。这里我们使用repeat 来构建每个元素的虚拟重复。又是一件好事,我们实际上不必创建新数组。 repeat 生成器只会生成输入元素 N 次。

    最后,我们想要一种方法将所有这些重复的元素串成一个扁平化的枚举。这就是chain.from_iterable() 的用武之地。它使用一个可迭代的可迭代对象,依次展开每个可迭代对象。与其他部分一样,chain 将生成一个新的生成器,而不是一个新的列表,因此我们再次节省了内存。如果您确实想要一个列表,您可以在最后将其提供给list()。或者只是将其作为for in 构造的输入。

    以下是使用意图揭示变量分解成各个操作的所有内容:

    elements = my_array[::2]
    counts = my_array[1::2]
    bypairs = zip(elements, counts)
    repeated = (repeat(elem, count) for elem, count in bypairs)
    flattened = chain.from_iterable(repeated)
    list(flattened)
    

    【讨论】:

      【解决方案4】:

      这是另一种方法,跳过itertools,支持生成器:

      def expanded(matrix):
          stream = iter(matrix)
          for element, count in zip(stream, stream):
              for _ in range(count):
                  yield element
      
      list(expanded(my_array))
      

      【讨论】:

        【解决方案5】:

        使用列表推导:

        In [3]: my_array = ['name_1', 3, 'name_2', 2]
        In [4]: out = [i for i, j in zip(my_array[::2], my_array[1::2]) for _ in range(j)]
        In [5]: out
        Out[5]: ['name_1', 'name_1', 'name_1', 'name_2', 'name_2']
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2021-05-10
          • 2017-05-20
          • 2022-07-07
          • 1970-01-01
          • 1970-01-01
          • 2023-01-19
          • 1970-01-01
          相关资源
          最近更新 更多