python - 将具有索引格式的大型 .json 文件读入 Pandas 数据帧
问题描述
我一直在关注这个答案,但在与它的作者讨论之后,它似乎只提供了orient='records'
数据格式的解决方案。
这是区别:
# orient='records'
[
{"Product":"Desktop Computer","Price":700},
{"Product":"Tablet","Price":250},
{"Product":"iPhone","Price":800},
{"Product":"Laptop","Price":1200}
]
# orient='index'
{
"0":{"Product":"Desktop Computer","Price":700},
"1":{"Product":"Tablet","Price":250},
"2":{"Product":"iPhone","Price":800},
"3":{"Product":"Laptop","Price":1200}
}
我有索引格式,因为我的数据是从 SQL 数据库读入数据帧,并且需要索引字段来指定每条记录。
我的 json 文件是 2.5 GB,已从数据框中以orient='index'
格式导出。
df.to_json('test.json', orient='index')
这意味着整个文件实际上是一个巨大的字符串,而不是像记录集合这样的列表:
{"0":{"Product":"Desktop Computer","Price":700},"1":{"Product":"Tablet","Price":250},"2":{"Product":"iPhone","Price":800},"3":{"Product":"Laptop","Price":1200}}
这意味着我不能像这样使用任何基于行或块的迭代解决方案:
df = pd.read_json('test.json', orient='index', lines=True, chunksize=5)
根据文档,lines=True
只能在记录采用类似列表的格式时使用,这就是为什么pandas.DataFrame.to_json
除非 orient 不是,否则甚至不接受此参数的原因orient='records'
。的限制chunksize=
也来自于此,它说:
"This can only be passed if lines=True. If this is None, the file will be read into memory all at once."
正是这就是问题的原因,试图读取如此巨大的 .json 文件会返回:
df = pd.read_json('test.json', orient='index')
File "C:\Users\Username\AppData\Local\Programs\Python\Python37\lib\site-
packages\pandas\io\json\_json.py", line 1100,
in _parse_no_numpy
loads(json, precise_float=self.precise_float),
MemoryError
我也在考虑将索引值添加为第一列,在这种情况下,它不会因记录格式而丢失;或者甚至可以单独存储一个索引列表。只是我担心它会在以后降低搜索性能。
是否有任何解决方案可以严格使用 .json 文件而不使用其他基于数据库或大数据的技术来处理这种情况?
更新#1
这里的请求是我的数据的实际结构。SQL表:
Serial Date PatientID Type Gender YearWeek
0 425571118001461E 2011-06-30 20:59:30 186092 3 1.0 2011-w26
1 425571118001461E 2011-06-30 20:55:30 186092 3 1.0 2011-w26
2 425571118001461E 2013-08-28 09:29:30 186092 3 1.0 2013-w35
3 425571118001461E 2013-08-28 07:44:30 186092 3 1.0 2013-w35
4 425571118001461E 2013-08-27 20:44:30 186092 3 1.0 2013-w35
... ... ... ... ... ... ...
32290281 4183116300254921 2020-04-09 08:07:50 217553 8 2.0 2020-w15
32290282 4183116300254921 2020-04-08 10:29:50 217553 8 2.0 2020-w15
32290283 4141119420031548 2020-04-20 10:18:02 217555 12 2.0 2020-w17
32290284 4141119420043226 2020-04-20 12:33:11 217560 12 NaN 2020-w17
32290285 4141119420000825 2020-04-20 17:31:44 217568 12 1.0 2020-w17
pandas 数据透视表与示例中的几乎相同,但有 50,000 行和 4,000 列:
df = df.pivot_table(index='PatientID', values='Serial', columns='YearWeek', aggfunc=len, fill_value=0)
YearWeek 1969-w01 1969-w02 1969-w03 1969-w04 1969-w05 ... 2138-w17 2138-w18 2138-w19 2138-w20 2138-w21
PatientID
0 0 0 0 0 0 ... 0 0 0 0 0
455 1 0 3 0 0 ... 0 0 0 0 0
40036 0 0 0 0 0 ... 0 0 0 0 0
40070 0 0 0 0 0 ... 0 0 0 0 0
40082 0 0 0 0 0 ... 0 0 0 0 0
... ... ... ... ... ... ... ... ... ... ... ...
217559 0 0 0 0 0 ... 0 0 0 0 0
217560 0 0 0 0 0 ... 0 0 0 0 0
217561 0 0 0 0 0 ... 0 0 0 0 0
217563 0 0 0 0 0 ... 0 0 0 0 0
217568 0 1 0 2 0 ... 0 0 0 0 0
这就是使用索引格式的 json 保存它的方式:
{
"0":{"1969-w01":0,"1969-w02":0,"1969-w03":0,"1969-w04":0, ...},
"455":{"1969-w01":1,"1969-w02":0,"1969-w03":3,"1969-w04":0, ...},
"40036":{"1969-w01":0,"1969-w02":0,"1969-w03":0,"1969-w04":0, ...},
...
"217568":{"1969-w01":0,"1969-w02":1,"1969-w03":0,"1969-w04":2, ...}
}
只有我不能给出line=True
arg,所以它实际上被限制在一个巨大的字符串中,使它成为一个单行 json:
{"0":{"1969-w01":0,"1969-w02":0,"1969-w03":0,"1969-w04":0, ...},"455":{"1969-w01":1,"1969-w02":0,"1969-w03":3,"1969-w04":0, ...},"40036":{"1969-w01":0,"1969-w02":0,"1969-w03":0,"1969-w04":0, ...}, ... "217568":{"1969-w01":0,"1969-w02":1,"1969-w03":0,"1969-w04":2, ...}}
解决方案
一些解决方案,从最简单到涉及更多:
1.SQL
如果您可以在数据库上执行查询,也许最好的解决方案是尝试以更好的格式写入数据?或者,您可以尝试直接从数据库中读取 - Pandas 也可以这样做:) 这是pd.read_sql() 的文档。
2. 有orient=...
必要吗?
要按照您给出的示例读取 JSON 文件,并创建与您的数据透视表示例(JSON 键作为数据框索引)类似的形式的 DataFrame,您可以尝试以下简单方法:
# read and transpose!
df = pd.read_json("test.json").T
但是,这可能无法解决内存问题。
3.拆分成多个文件
也许最快的方法是简单地将大文件切割成更小的文件,每个文件都可以读入 Pandas 数据帧(限制任何给定时间所需的工作内存),然后pd.merge
是pd.concat
生成的数据帧。
Linux 中有一个很好的工具叫做split
,它可以做到这一点。我注意到您正在使用 Windows(如果您启用它,较新的 Windows 版本会提供 Linux 终端!)。否则也许有一个类似的工具,但我害怕我不知道。
如果您只需要这样做一次然后继续您的生活,您也许可以使用 Emacs 或 VS Code 等文本编辑器打开文件,然后将部分复制粘贴到新文件中......蹩脚,但可能会工作 ¯ \_(ツ)_/¯
4. 流式阅读器
一个名为的包ijson
将迭代加载一个 JSON 文件,它允许您定义中断或对每个嵌套分区进行处理 - 然后您可以例如records
为 Pandas on-the-fly创建格式。这个解决方案还承诺低内存消耗,作为一个迭代器(又名生成器)——不过你需要了解它是如何工作的。看看这里有一个很好的解释。
另一个名为json-streamer 的包也可以读取部分 JSON 内容,尽管它可能有点远,因为你有一个静态文件。
推荐阅读
- php - 正则表达式前 3 个字母以某种方式表示某事
- ios - 创建子 UIView 的 UIView 正在生成层次约束警告
- python - 编写 Python 脚本来自动化 llvm 代码覆盖率测试
- java - 使用 Kafka-Spark Streaming API 处理流数据时重复
- ios - 如何访问创建的目录?- NSCocoaErrorDomain 代码=257
- javascript - Javascript:数组不保留值
- xml - NetSuite 实时运费计算器调整请求
- deployment - 在 jboss 中部署应用程序时出现 ClassNotFoundException
- c# - 使用 lex.Match 而不是 lex.Autocomplete 时 Redis Lexicographicset 超时错误
- python - Python3:字符串索引必须是整数