我正在使用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是否可以通过其自身的内部功能来做到这一点。
答案 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)
熊猫看起来还不错!