将numpy中的单列JSON拆分为多列数组

时间:2019-02-15 06:35:10

标签: python json numpy

我正在使用Elastic Search,并在查询后得到结果。借助Pandas,我可以将生成的JSON拆分为多个列,从而可以对任何单个列执行任何操作。

我想对numpy做同样的事情。但是,如果我使用numpy,则只能实现单列JSON。

data = np.array(result_dict['aggregations']['date']['buckets'])


array([{u'key_as_string': u'2019-01-16T00:00:00.000+05:30', u'key': 1547577000000, u'doc_count': 1},
       {u'key_as_string': u'2019-01-17T00:00:00.000+05:30', u'key': 1547663400000, u'doc_count': 3},
       {u'key_as_string': u'2019-01-18T00:00:00.000+05:30', u'key': 1547749800000, u'doc_count': 3},
       {u'key_as_string': u'2019-01-19T00:00:00.000+05:30', u'key': 1547836200000, u'doc_count': 3}],
      dtype=object)

问题在于,在这种情况下,如果我必须访问doc_count值,则必须再编写一行代码。知道numpy非常快,如果在数组初始化时有一种方法可以通过numpy本身对此JSON进行3列拆分,那么处理大型数据集会更快。

这样我就可以按列访问数据,如:

data[:, 'doc_count']

使访问各个列变得容易。

请注意,我要避免python循环来执行此操作。已经做过熊猫了。我想知道numpy是否可以通过其自身的内部功能来做到这一点。

2 个答案:

答案 0 :(得分:0)

您必须操纵数据以获得表/ json的矩阵表示,您可以尝试:

import numpy as np


r = np.array([{'key_as_string': '2019-01-16T00:00:00.000+05:30', 'key': 1547577000000, 'doc_count': 1},
       {'key_as_string': '2019-01-17T00:00:00.000+05:30', 'key': 1547663400000, 'doc_count': 3},
       {'key_as_string': '2019-01-18T00:00:00.000+05:30', 'key': 1547749800000, 'doc_count': 3},
       {'key_as_string': '2019-01-19T00:00:00.000+05:30', 'key': 1547836200000, 'doc_count': 3}],
      dtype=object)

header = r[0].keys()
rows = np.append([list(header)],  [[e[h] for h in header] for e in  r] , axis=0)

print(rows)
# array([['key_as_string', 'key', 'doc_count'],
#        ['2019-01-16T00:00:00.000+05:30', '1547577000000', '1'],
#        ['2019-01-17T00:00:00.000+05:30', '1547663400000', '3'],
#        ['2019-01-18T00:00:00.000+05:30', '1547749800000', '3'],
#        ['2019-01-19T00:00:00.000+05:30', '1547836200000', '3']],
#       dtype='<U29')

rows[:, 2]
# array(['doc_count', '1', '3', '3', '3'], dtype='<U29')

如果您不想在列中包含标题:

header = list(r[0].keys())
rows = np.array([[e[h] for h in header] for e in  r])

print(rows)
#array([['2019-01-16T00:00:00.000+05:30', '1547577000000', '1'],
#       ['2019-01-17T00:00:00.000+05:30', '1547663400000', '3'],
#       ['2019-01-18T00:00:00.000+05:30', '1547749800000', '3'],
#       ['2019-01-19T00:00:00.000+05:30', '1547836200000', '3']],
#     dtype='<U29')
rows[:, header.index('doc_count')]
# array(['1', '3', '3', '3'], dtype='<U29')

答案 1 :(得分:0)

虽然熊猫可以通过简单的调用从列表中创建数据框,但这并不意味着它很快。

In [260]: alist =[{u'key_as_string': u'2019-01-16T00:00:00.000+05:30', u'key': 1
     ...: 547577000000, u'doc_count': 1},
     ...:        {u'key_as_string': u'2019-01-17T00:00:00.000+05:30', u'key': 15
     ...: 47663400000, u'doc_count': 3},
     ...:        {u'key_as_string': u'2019-01-18T00:00:00.000+05:30', u'key': 15
     ...: 47749800000, u'doc_count': 3},
     ...:        {u'key_as_string': u'2019-01-19T00:00:00.000+05:30', u'key': 15
     ...: 47836200000, u'doc_count': 3}]
     ...:        
In [261]: pd.DataFrame(alist)
Out[261]: 
   doc_count              ...                                key_as_string
0          1              ...                2019-01-16T00:00:00.000+05:30
1          3              ...                2019-01-17T00:00:00.000+05:30
2          3              ...                2019-01-18T00:00:00.000+05:30
3          3              ...                2019-01-19T00:00:00.000+05:30

[4 rows x 3 columns]
In [262]: _.dtypes
Out[262]: 
doc_count         int64
key               int64
key_as_string    object
dtype: object
In [263]: timeit pd.DataFrame(alist)
694 µs ± 19.5 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

在我的评论中,我专注于逐个键地访问字典,但是忘记了我们可以快速访问所有值作为列表。

In [264]: [tuple(d.values()) for d in alist]
Out[264]: 
[('2019-01-16T00:00:00.000+05:30', 1547577000000, 1),
 ('2019-01-17T00:00:00.000+05:30', 1547663400000, 3),
 ('2019-01-18T00:00:00.000+05:30', 1547749800000, 3),
 ('2019-01-19T00:00:00.000+05:30', 1547836200000, 3)]
In [265]: timeit [tuple(d.values()) for d in alist]
1.43 µs ± 11.6 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

pandas相比非常快。

我使用了tuple,因此该列表可以传递给结构化数组:

In [266]: dt = np.dtype([('key_as_string', 'U40'),('doc_count', int),('id',int)]
     ...: )
In [267]: np.array([tuple(d.values()) for d in alist],dt)
Out[267]: 
array([('2019-01-16T00:00:00.000+05:30', 1547577000000, 1),
       ('2019-01-17T00:00:00.000+05:30', 1547663400000, 3),
       ('2019-01-18T00:00:00.000+05:30', 1547749800000, 3),
       ('2019-01-19T00:00:00.000+05:30', 1547836200000, 3)],
      dtype=[('key_as_string', '<U40'), ('doc_count', '<i8'), ('id', '<i8')])
In [268]: timeit np.array([tuple(d.values()) for d in alist],dt)
5.12 µs ± 34.7 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

或将字符串转换为日期时间

In [269]: dt1 = np.dtype([('key_as_string', 'datetime64[m]'),('doc_count', int),
     ...: ('id',int)])
In [270]: np.array([tuple(d.values()) for d in alist],dt1)
/usr/local/bin/ipython3:1: DeprecationWarning: parsing timezone aware datetimes is deprecated; this will raise an error in the future
  #!/usr/bin/python3
Out[270]: 
array([('2019-01-15T18:30', 1547577000000, 1),
       ('2019-01-16T18:30', 1547663400000, 3),
       ('2019-01-17T18:30', 1547749800000, 3),
       ('2019-01-18T18:30', 1547836200000, 3)],
      dtype=[('key_as_string', '<M8[m]'), ('doc_count', '<i8'), ('id', '<i8')])

这慢了一点,但熊猫快了很多。

并仅需跨字典访问一个键:

In [273]: [d['doc_count'] for d in alist]
Out[273]: [1, 3, 3, 3]
In [274]: np.array([d['doc_count'] for d in alist])
Out[274]: array([1, 3, 3, 3])
In [275]: timeit np.array([d['doc_count'] for d in alist])
2.69 µs ± 126 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

让我们测试更大的列表:

In [308]: blist = alist * 1000
In [309]: timeit np.array([d['doc_count'] for d in blist])
430 µs ± 67.6 ns per loop (mean ± std. dev. of 7 runs, 1000 loops each)
In [310]: timeit np.array([tuple(d.values()) for d in blist],dt)
2.18 ms ± 4.01 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
In [311]: timeit pd.DataFrame(blist)
5.6 ms ± 140 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

熊猫看起来还不错!