簡體   English   中英

將帶有索引格式的 large.json 文件讀入 Pandas dataframe

[英]Read large .json file with index format into Pandas dataframe

我一直在關注這個答案,但在與它的作者討論之后,它似乎只為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 數據庫讀入 dataframe 並且需要索引字段來指定每條記錄。

我的 json 文件為 2.5 GB ,已從 dataframe 以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 pivot 表與示例中的表幾乎相同,但有 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 文件,並創建一個與您的數據透視表示例相當的形式的 DataFrame(JSON 鍵為 dataframe 索引,您可以嘗試以下簡單方法:

# read and transpose!
df = pd.read_json("test.json").T

但是,這可能無法解決 memory 問題。

3.拆分成多個文件

也許最快的方法是簡單地將大文件切割成更小的文件,每個文件都可以讀取到 Pandas Dataframe (限制工作pd.concat pd.merge

Linux 中有一個很好的工具,叫做split ,它可以做到 我注意到您正在使用 windows(如果您啟用它,較新的 windows 版本會提供 Linux 終端。),否則可能有類似的工具。 但我不知道我害怕。

如果您只需要這樣做一次然后繼續您的生活,您也許可以使用 Emacs 或 VS Code 等文本編輯器打開您的文件,然后將部分復制粘貼到新文件中......蹩腳,但可能會工作¯ \_(ツ)_/¯

4. 流式閱讀器

一個名為 ijson 的ijson將迭代加載 JSON 文件,該文件允許您定義中斷或對每個嵌套分區進行處理 - 例如,您可以創建 Z251D2BBFE9A3B95E5691CEB3DCrecords格式。 該解決方案還承諾低 memory 消耗,作為一個迭代器(又名生成器) - 你需要了解它是如何工作的。 看看這里有一個很好的解釋

另一個名為json-streamer 的package 也可以讀取部分 JSON 內容,盡管它可能有點遠,因為您有一個 static 文件。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM