【问题标题】:How can I efficiently merge these two datasets?如何有效地合并这两个数据集?
【发布时间】:2014-08-17 03:50:53
【问题描述】:

所以我有两个数据列表,看起来像这样(缩短):

[[1.0, 1403603100],
 [0.0, 1403603400],
 [2.0, 1403603700],
 [0.0, 1403604000],
 [None, 1403604300]]

[1.0, 1403603100],
[0.0, 1403603400],
[1.0, 1403603700],
[None, 1403604000],
[5.0, 1403604300]]

我想要做的是合并它们,将每个数据集的第一个元素相加,或者如果任一计数器值为无,则将其设为 0.0。所以上面的例子会变成这样:

[[2.0, 1403603100],
[0.0, 1403603400],
[3.0, 1403603700],
[0.0, 1403604000],
[0.0, 1403604300]]

这是我目前为止的想法,如果有点笨拙,请见谅。

def emit_datum(datapoints):
    for datum in datapoints:
        yield datum

def merge_data(data_set1, data_set2):

    assert len(data_set1) == len(data_set2)
    data_length = len(data_set1)

    data_gen1 = emit_datum(data_set1)
    data_gen2 = emit_datum(data_set2)

    merged_data = []

    for _ in range(data_length):

        datum1 = data_gen1.next()
        datum2 = data_gen2.next()

        if datum1[0] is None or datum2[0] is None:
            merged_data.append([0.0, datum1[1]])
            continue

        count = datum1[0] + datum2[0]
        merged_data.append([count, datum1[1]])

    return merged_data

我只能希望/假设我可以用 itertools 或集合做一些狡猾的事情?

【问题讨论】:

  • 你可以分别发布两个数据集以便轻松复制和粘贴它们
  • 使用iter 而不是emit_datum
  • 让复制/粘贴数据变得更容易
  • 在您的示例中,右侧的列始终处于相同的顺序,我们可以假设这是真的吗?
  • 是的,它们实际上是时间戳。

标签: python arrays merge


【解决方案1】:

如果你让两个值都等于 0.0,如果其中一个是 None,你只需要一个简单的循环。

 l1 = [1.0, 1403603100],
 [0.0, 1403603400],
 [2.0, 1403603700],
 [0.0, 1403604000],
 [None, 1403604300]]

l2 = [[1.0, 1403603100],
[0.0, 1403603400],
[1.0, 1403603700],
[None, 1403604000],
[5.0, 1403604300]]

final = []
assert len(l1)== len(l2)
for x, y in zip(l1, l2):
    if x[0] is  None or y[0] is  None:
        y[0] = 0.0
        final.append(y)
    else:
        final.append([x[0] + y[0], x[-1]])
print final

[[2.0, 1403603100], [0.0, 1403603400], [3.0, 1403603700], [0.0, 1403604000], [0.0, 1403604300]]


In [51]: %timeit merge_data(l1,l2)
100000 loops, best of 3: 5.76 µs per loop


 In [52]: %%timeit                 
   ....: final = []
   ....: assert len(l1)==len(l2)
   ....: for x, y in zip(l1, l2):
   ....:     if x[0] is  None or y[0] is None:
   ....:         y[0] = 0.0
   ....:         final.append(y)
   ....:     else:
   ....:         final.append([x[0] + y[0], x[-1]])
   ....: 
100000 loops, best of 3: 2.64 µs per loop

【讨论】:

  • numpy 解决方案可能更快,但这是迄今为止最快和最简单的。干杯!
  • 别担心,我编辑了,我改成if x[0] is None or y[0] is None
【解决方案2】:

如何根据标识符对数据进行“分箱”,即收集与一个标识符对应的所有值(例如 1403603400),然后将其汇总。字典非常适​​合收集与标识符(键)对应的所有值,而 list 类型的 defaultdict 使这变得特别简单:

>>> data = [[1.0, 1403603100],  [1.0, 1403603100],
...  [0.0, 1403603400],  [0.0, 1403603400],
...  [2.0, 1403603700],  [1.0, 1403603700],
...  [0.0, 1403604000],  [None, 1403604000],
...  [None, 1403604300],  [5.0, 1403604300]]

>>> from collections import defaultdict
>>> d = defaultdict(list)
>>> for value, identifier in data:
...     d[identifier].append(value)
... 

现在我们已经对数据进行了排序并可以有条件地求和:

>>> for identifier, valuelist in d.iteritems():
...     if not None in valuelist:
...         print identifier, sum(valuelist)
...     else:
...         print identifier, 0.0
... 
1403603400 0.0
1403603700 3.0
1403603100 2.0
1403604300 0.0
1403604000 0.0

简而言之,获取你想要的列表:

>>> [[i, sum(v)] if None not in v else [i, .0] for i, v in d.iteritems()]
[[1403603400, 0.0], [1403603700, 3.0], [1403603100, 2.0], [1403604300, 0.0], [1403604000, 0.0]]

这种方法首先需要混合数据集,就像您在示例输入的第一个版本中所做的那样。

【讨论】:

  • 这两个数据集都有自己的列表,不确定我将如何重新考虑您的解决方案以考虑到这一点。
  • .extend() 一个列表与另一个列表,使它们成为一个。 (你的第一个版本不同,我只是复制了你的代码,现在它改变了)。
  • 除此之外,您需要更好地指定合并应该如何发生。在我的解决方案中,一个数据集和另一个数据集之间是否匹配并不重要。您是否只想合并匹配项并忽略仅包含在其中一个列表中的那些数据点?如果是,那么我现在的解决方案不起作用。如果不是,则不需要区分为多个数据集,您只有一个大数据点集合。
【解决方案3】:

使用 numpy 数组,你不需要做任何循环。如果你处理更大的数据集,这会让你的代码更快。

import numpy as np

In [68]: a = np.asarray(a)


In [69]: b = np.asarray(b)

In [71]: a_none_idx = np.equal(a,None)

In [72]: b_none_idx = np.equal(b,None)

In [73]: a[a_none_idx]=0

In [74]: b[b_none_idx]=0

In [76]: c = np.zeros(a.shape)

In [77]: c[:,0]= a[:,0] + b[:,0]

In [78]: c
Out[78]: 
array([[ 2.,  0.],
       [ 0.,  0.],
       [ 3.,  0.],
       [ 0.,  0.],
       [ 5.,  0.]])

In [79]: c[a_none_idx]=0

In [80]: c[b_none_idx]=0

In [81]: c[:,1] = a[:,1]

In [82]: c
Out[82]: 
array([[  2.00000000e+00,   1.40360310e+09],
       [  0.00000000e+00,   1.40360340e+09],
       [  3.00000000e+00,   1.40360370e+09],
       [  0.00000000e+00,   1.40360400e+09],
       [  0.00000000e+00,   1.40360430e+09]]

【讨论】:

  • 你应该提到 np 是 numpy。很多人都知道,但不是每个人都知道:)
【解决方案4】:

你可以使用zip,像这样:

def merge(list1, list2):
    returnlist = []
    for x, y in zip(list1, list2):
        if x[0] is None or y[0] is None:
            returnlist.append([0.0, x[1]])
        else:
            returnlist.append([x[0] + y[0], x[1]])

    return returnlist

zip 在元组上返回一个迭代器,其中包含来自每个输入列表的具有相同索引的元素(即(list1[0], list2[0])(list1[1], list2[1]) 等)

【讨论】:

    猜你喜欢
    • 2011-11-18
    • 1970-01-01
    • 2010-11-03
    • 1970-01-01
    • 1970-01-01
    • 2017-07-31
    • 2022-06-10
    • 1970-01-01
    相关资源
    最近更新 更多