PDEP-12: コンパクトで可逆なJSONインターフェース
- 作成日: 2023年6月16日
- ステータス: 却下
- 議論: #53252 #55038
- 著者: Philippe THOMY
- 改訂: 3
概要
- 概要
- 問題の説明
- 機能説明
- スコープ
- 動機
- コンパクトで可逆なJSONインターフェースが重要な理由とは?
- 拡張型を考慮することは適切か?
- これはpandasにのみ役立つか?
- 説明
- データ型付け
- TableSchemaとpandasの対応
- JSON形式
- 変換
- 使用法と影響
- 使用法
- 互換性
- pandasフレームワークへの影響
- 実施するリスク / 実施しないリスク
- 実装
- モジュール
- 実装オプション
- F.A.Q.
- 要約
- コアチームの決定
- タイムライン
- PDEP履歴
概要
問題の説明
現在のJSONインターフェースでは、dtypeと「Python型」が明示的に考慮されていません。
そのため、JSONインターフェースは常に可逆ではなく、dtypeの考慮に関連する矛盾を抱えています。
もう一つの結果として、orient="table"オプションにおけるTable Schema仕様の部分的な適用があります(定義された24のTable Schemaデータ型のうち、6つが考慮されています)。
いくつかのJSONインターフェースの問題は、リンクされたNoteBookで詳しく説明されています。
機能説明
シンプルでコンパクトかつ可逆なソリューションとして、私は型の概念を統合したJSON-NTV形式(Named and Typed Value)と、表形式データ用のそのバリエーションであるJSON-TABの使用を提案します(JSON-NTV形式はIETFインターネットドラフトで定義されています(まだRFCではありません!!))。
このソリューションは、多数の型(必ずしもpandasのdtypeではない)を含めることを可能にし、次のものを提供します。
- Table Schema仕様を尊重するTable Schema JSONインターフェース(
orient="table")(6型から20型に増加)、 - すべてのpandasデータ形式に対応するグローバルJSONインターフェース。
グローバルJSONインターフェースの例
以下の例では、いくつかのデータ型を持つDataFrameがJSONに変換されます。
このJSONから得られるDataFrameは、元のDataFrameと同一です(可逆性)。
既存のJSONインターフェースでは、この変換は不可能です。
この例では、ntv-pandasリポジトリで定義されているntv_pandasモジュールを使用しています。
データ例
In [1]: from shapely.geometry import Point
from datetime import date
import pandas as pd
import ntv_pandas as npd
In [2]: data = {'index': [100, 200, 300, 400, 500, 600],
'dates::date': [date(1964,1,1), date(1985,2,5), date(2022,1,21), date(1964,1,1), date(1985,2,5), date(2022,1,21)],
'value': [10, 10, 20, 20, 30, 30],
'value32': pd.Series([12, 12, 22, 22, 32, 32], dtype='int32'),
'res': [10, 20, 30, 10, 20, 30],
'coord::point': [Point(1,2), Point(3,4), Point(5,6), Point(7,8), Point(3,4), Point(5,6)],
'names': pd.Series(['john', 'eric', 'judith', 'mila', 'hector', 'maria'], dtype='string'),
'unique': True }
In [3]: df = pd.DataFrame(data).set_index('index')
In [4]: df
Out[4]: dates::date value value32 res coord::point names unique
index
100 1964-01-01 10 12 10 POINT (1 2) john True
200 1985-02-05 10 12 20 POINT (3 4) eric True
300 2022-01-21 20 22 30 POINT (5 6) judith True
400 1964-01-01 20 22 10 POINT (7 8) mila True
500 1985-02-05 30 32 20 POINT (3 4) hector True
600 2022-01-21 30 32 30 POINT (5 6) maria True
JSON表現
In [5]: df_to_json = npd.to_json(df)
pprint(df_to_json, width=120)
Out[5]: {':tab': {'coord::point': [[1.0, 2.0], [3.0, 4.0], [5.0, 6.0], [7.0, 8.0], [3.0, 4.0], [5.0, 6.0]],
'dates::date': ['1964-01-01', '1985-02-05', '2022-01-21', '1964-01-01', '1985-02-05', '2022-01-21'],
'index': [100, 200, 300, 400, 500, 600],
'names::string': ['john', 'eric', 'judith', 'mila', 'hector', 'maria'],
'res': [10, 20, 30, 10, 20, 30],
'unique': [True, True, True, True, True, True],
'value': [10, 10, 20, 20, 30, 30],
'value32::int32': [12, 12, 22, 22, 32, 32]}}
可逆性
In [5]: df_from_json = npd.read_json(df_to_json)
print('df created from JSON is equal to initial df ? ', df_from_json.equals(df))
Out[5]: df created from JSON is equal to initial df ? True
その他いくつかの例は、リンクされたNoteBookで提供されています。
Table Schema JSONインターフェースの例
以下の例では、いくつかのTable Schemaデータ型を持つDataFrameがJSONに変換されます。
このJSONから得られるDataFrameは、元のDataFrameと同一です(可逆性)。
既存のTable Schema JSONインターフェースでは、この変換は不可能です。
In [1]: from shapely.geometry import Point
from datetime import date
In [2]: df = pd.DataFrame({
'end february::date': ['date(2023,2,28)', 'date(2024,2,29)', 'date(2025,2,28)'],
'coordinates::point': ['Point([2.3, 48.9])', 'Point([5.4, 43.3])', 'Point([4.9, 45.8])'],
'contact::email': ['[email protected]', '[email protected]', '[email protected]']
})
In [3]: df
Out[3]: end february::date coordinates::point contact::email
0 2023-02-28 POINT (2.3 48.9) john.doe@table.com
1 2024-02-29 POINT (5.4 43.3) lisa.minelli@schema.com
2 2025-02-28 POINT (4.9 45.8) walter.white@breaking.com
JSON表現
In [4]: df_to_table = npd.to_json(df, table=True)
pprint(df_to_table, width=140, sort_dicts=False)
Out[4]: {'schema': {'fields': [{'name': 'index', 'type': 'integer'},
{'name': 'end february', 'type': 'date'},
{'name': 'coordinates', 'type': 'geopoint', 'format': 'array'},
{'name': 'contact', 'type': 'string', 'format': 'email'}],
'primaryKey': ['index'],
'pandas_version': '1.4.0'},
'data': [{'index': 0, 'end february': '2023-02-28', 'coordinates': [2.3, 48.9], 'contact': '[email protected]'},
{'index': 1, 'end february': '2024-02-29', 'coordinates': [5.4, 43.3], 'contact': '[email protected]'},
{'index': 2, 'end february': '2025-02-28', 'coordinates': [4.9, 45.8], 'contact': '[email protected]'}]}
可逆性
In [5]: df_from_table = npd.read_json(df_to_table)
print('df created from JSON is equal to initial df ? ', df_from_table.equals(df))
Out[5]: df created from JSON is equal to initial df ? True
その他いくつかの例は、リンクされたNoteBookで提供されています。
スコープ
目的は、提案されたJSONインターフェースをあらゆる種類のデータ、およびorient="table"オプションまたは新しいオプションorient="ntv"で利用可能にすることです。
提案されたインターフェースは、既存のデータと互換性があります。
動機
orient=tableオプションを他のデータ型に拡張する理由は何ですか?
- Table Schema仕様では24種類のデータ型が定義されており、そのうち6種類がpandasインターフェースで考慮されています。
コンパクトで可逆なJSONインターフェースが重要な理由とは?
- 可逆インターフェースは交換フォーマットを提供します。
- テキスト交換フォーマットはプラットフォーム間の交換を容易にします(例:OpenData)。
- JSON交換フォーマットはAPIレベルで使用できます。
拡張型を考慮することは適切か?
- 追加のデータスキーマの追加を避けます。
- pandasが処理するデータのセマンティックなスコープを広げます。
- いくつかの問題(例:#12997, #14358, #16492, #35420, #35464, #36211, #39537, #49585, #50782, #51375, #52595, #53252)への解決策となります。
- 補完的な型の使用により、pandasのデータモデルを変更する必要がありません。
これはpandasにのみ役立つか?
- JSON-TAB形式は、表形式データと多次元データに適用できます。
- したがって、このJSONインターフェースは、表形式データまたは多次元データを使用するあらゆるアプリケーションで使用できます。これにより、例えば、pandas - DataFrameとXarray - DataArray間での可逆データ交換が可能になります(Xarrayの問題は検討中)。DataFrame / DataArrayの例を参照してください。
説明
提案されたソリューションはいくつかの重要な点に基づいています
- データ型付け
- TableSchemaとpandasの対応
- 表形式データ用のJSON形式
- JSON形式への変換とからの変換
データ型付け
データ型はNTVプロジェクトで定義され、管理されています(名前、JSONエンコーダー、デコーダー)。
PandasのdtypeはNTV型と互換性があります。
| pandas dtype | NTV型 |
|---|---|
| intxx | intxx |
| uintxx | uintxx |
| floatxx | floatxx |
| datetime[ns] | datetime |
| datetime[ns, |
datetimetz |
| timedelta[ns] | durationiso |
| string | string |
| boolean | boolean |
注
- タイムゾーン付きのdatetimeは単一のNTV型です(string ISO8601)。
CategoricalDtypeとSparseDtypeは表形式JSON形式に含まれています。objectdtypeはコンテキストに依存します(以下を参照)。PeriodDtypeとIntervalDtypeは未定義です。
JSON型(暗黙的または明示的)は、pandas JSONインターフェースに従ってdtypeに変換されます。
| JSON型 | pandas dtype |
|---|---|
| number | int64 / float64 |
| string | string / object |
| array | object |
| object | object |
| true, false | boolean |
| null | NaT / NaN / None |
注
- NTV型が定義されている場合、
dtypeはそれに合わせて調整されます。 - null型データの考慮については明確化が必要です。
他のNTV型はobject dtypeに関連付けられます。
TableSchemaとpandasの対応
TableSchemaの型付けは、2つの属性formatとtypeによって行われます。
以下の表は、TableSchemaのformat/typeとpandasのNTVtype/dtypeの対応を示しています。
| format / type | NTV型 / dtype |
|---|---|
| default / datetime | / datetime64[ns] |
| default / number | / float64 |
| default / integer | / int64 |
| default / boolean | / bool |
| default / string | / object |
| default / duration | / timedelta64[ns] |
| email / string | email / string |
| uri / string | uri / string |
| default / object | object / object |
| default / array | array / object |
| default / date | date / object |
| default / time | time / object |
| default / year | year / int64 |
| default / yearmonth | month / int64 |
| array / geopoint | point / object |
| default / geojson | geojson / object |
注
- その他のTableSchema形式が定義されており、検討が必要です(uuid、binary、topojson、geopointおよびdatationの特定形式)。
- 最初の6行は既存のものです。
JSON形式
TableSchemaインターフェースのJSON形式は既存のものです。
グローバルインターフェースのJSON形式はJSON-TAB仕様で定義されています。これには、JSON-NDプロジェクトで元々定義された命名規則と、カテゴリカルデータのサポートが含まれています。仕様はスパースデータを含めるように更新する必要があります。
変換
データが非object dtypeに関連付けられている場合、pandasの変換メソッドが使用されます。そうでない場合は、NTV変換が使用されます。
pandas -> JSON
NTV型が定義されていない場合:to_json()を使用NTV型が定義されており、dtypeがobjectではない場合:to_json()を使用NTV型が定義されており、dtypeがobjectの場合:NTV変換を使用(pandas変換が存在しない場合)
JSON -> pandas
NTV型がdtypeと互換性がある場合:read_json()を使用NTV型がdtypeと互換性がない場合:NTV変換を使用(pandas変換が存在しない場合)
使用法と影響
使用法
この提案は重要な問題に答えているように思われます。
-
データ交換のための効率的なテキスト形式を持つこと
代替のCSV形式は可逆性がなく、陳腐化しています(最終改訂は2005年)。現在のCSVツールは標準に準拠していません。
-
pandasオブジェクトで「セマンティック」データを考慮に入れること
-
完全なTable Schemaインターフェースを持つこと
互換性
インターフェースはNTV型なしでも使用できます(既存のデータとの互換性 - 例を参照)。
インターフェースが利用可能であれば、JSONインターフェースに新しいorientオプションを追加することで、その機能の使用は他の機能から切り離されます。
pandasフレームワークへの影響
当初、影響は非常に限定的です。
SeriesまたはDataFrameの列のnameの変更(機能的な影響なし)、- Jsonインターフェースにオプションを追加(例:
orient='ntv')、および関連するメソッドを追加(他のメソッドとの機能的な干渉なし)。
後の段階では、いくつかの開発が検討される可能性があります。
SeriesまたはDataFrameの列のnameの検証、- NTV型を「補完的なオブジェクトdtype」として管理すること
- NTV型に依存する機能拡張
実施するリスク / 実施しないリスク
JSON-NTV形式とJSON-TAB形式は(まだ)認識され、使用されている形式ではありません。pandasにとってのリスクは、この機能が使用されないことです(機能的な影響はありません)。
一方、pandasによる早期の使用は、pandasの期待とニーズをよりよく考慮することを可能にし、pandasがサポートする型の進化についての考察を促します。
実装
モジュール
NTV用に2つのモジュールが定義されています。
-
json-ntv
このモジュールは、他のモジュールへの依存なしにNTVデータを管理します。
-
ntvconnector
これらのモジュールは、オブジェクトとJSONデータ間の変換を管理します。これらはオブジェクトモジュールに依存しています(例:shapelyロケーションとのコネクタはshapelyに依存しています)。
pandasにJSONインターフェースを統合するには、json-ntvモジュールのみをインポートする必要があります。
実装オプション
このインターフェースは、NTVコネクタ(SeriesConnectorおよびDataFrameConnector)として、また新しいpandas JSONインターフェースorientオプションとして実装できます。
いくつかのpandas実装が可能です。
-
外部
この実装では、インターフェースはNTV側でのみ利用可能です。このオプションは、JSONインターフェースのこの進化がpandasにとって有用でも戦略的でもないことを意味します。
-
NTV側
この実装では、インターフェースは両側で利用可能であり、変換はNTV内に配置されます。このオプションは、pandas側への影響を最小限に抑えるものです。
-
pandas側
この実装では、インターフェースは両側で利用可能であり、変換はpandas内に配置されます。このオプションにより、pandasはこの進化を制御し続けることができます。
-
pandas制限
この実装では、pandasインターフェースと変換はpandas内に配置され、非オブジェクト
dtypeのみが対象となります。このオプションにより、既存のdtypeと互換性のない型の導入を禁止しながら、コンパクトで可逆なインターフェースを提供できます。
F.A.Q.
Q: orient="table"は、すでに提案されていることをやっていないのですか?
A: 原則的には、はい、このオプションは型の概念を考慮に入れています。
しかし、これは非常に限定的です(Notebookに追加された例を参照)。
- 型とJsonインターフェース
- jsonインターフェースで型を維持する唯一の方法は、
orient='table'オプションを使用することです。 - json-tableインターフェースでは、period、timedelta64、intervalなどの少数のdtypeは許可されていません。
- 許可されている型がjson-tableインターフェースで常に維持されるとは限りません。
- 'object' dtypeのデータは、データが文字列の場合のみ保持されます。
- categorical dtypeでは、基になるdtypeはjsonインターフェースに含まれません。
- データのコンパクトさ
- json-tableインターフェースはコンパクトではありません(Notebookの例では、サイズがコンパクト形式の3倍または4倍になります)。
- 可逆性
- インターフェースは、int64、float64、bool、string、datetime64、および部分的にcategoricalの少数のdtypeでのみ可逆です。
- 外部型
- インターフェースは外部型を受け入れません。
- Table-schemaは20種類のデータ型を定義していますが、
orient="table"インターフェースは5種類のデータ型しか考慮していません(表を参照)。 - 外部型を統合するには、まずExtensionArrayおよびExtensionDtypeオブジェクトを作成する必要があります。
現在のインターフェースは、table-schemaで定義されているデータ構造と互換性がありません。これを可能にするには、提案されているような「型拡張」を統合する必要があります(これは、いくつかの形式のインターフェースに見られるextDtypeの概念で、部分的に達成されています)。
Q: 一般的に、read_json/to_jsonではpandas用に1つの「table」形式しか持つべきではありません。また、形式を変更した場合の後方互換性の問題もあります。「table」インターフェースにバグがあるからといって、新しいインターフェースを追加する理由にはなりません(むしろそれらのバグを修正したいです)。既存の形式は、型に関する問題やラウンドトリップに関する問題を修正する方法で適応させることはできないのでしょうか?
A: 2つの追加のコメントを追加します。
- Tableschemaで定義されている型は部分的にしか考慮されていません(インターフェースで考慮されていない型の例:string-uri、array、date、time、year、geopoint、string-email)。
read_json()インターフェースは、{'simple': [1,2,3]}のようなデータでも機能します(ドキュメントに示されている内容とは異なります)が、to_json()でこのシンプルなjsonを再作成することは不可能です。
この問題はバグ修正に限定されるものではなく、特にオープンデータソリューションで陳腐化したCSV形式がJson形式に徐々に置き換えられている現状を鑑みて、Jsonインターフェースに明確な戦略を定義する必要があると考えています。
述べたように、提案されたソリューションは現在のインターフェースのいくつかの欠点に対処し、orient='table'オプションに関係なく、単にpandas環境に適合することができます(もう一つの選択肢は、Jsonインターフェースがpandasの周辺機能であり、pandasの外部に留まることができると考えることです)。
それにもかかわらず、提案された形式とorient='table'形式を統合して、extDtypeの概念を明示的に管理することは可能です。
Q: 私が理解する限り、JSON NTVはいかなる形でも標準化されたJSON形式ではありません。私はpandas(そして、私がこの問題に興味を持つきっかけとなったgeopandas)は、デファクトまたはデジュリの標準に従うべきであり、現時点でコミュニティサポートのないファイル形式を選択すべきではないと考えています。これは将来的に明らかに変わる可能性があり、そのときにこのPRを再検討すべきです。なぜpandasはこの標準を使用するのでしょうか?
A: 問題に示されているように(そして添付のノートブックで詳述されているように)、jsonインターフェースは可逆的ではなく(to_jsonの後にread_jsonを実行しても常に元のオブジェクトが返されるわけではない)、いくつかの欠点やバグが存在します。この問題の主な原因は、データ型がJSON形式で考慮されていないこと(またはorient='table'オプションで非常に部分的にしか考慮されていないこと)です。
提案された内容は、この問題に答えるものです(ノートブックの冒頭の例は、この提案の関心事をシンプルかつ明確に示しています)。
基盤となるJSON-NTV形式に関して言えば、表形式データに対するその影響はかなり低い(フィールド名に型を追加するに限定される)です。しかし、この質問は適切です。JSON-NTV形式(IETFインターネットドラフト)は、共有され、文書化され、サポートされ、実装された形式ですが、確かに現時点でのコミュニティサポートは限られていますが、拡大を求めているだけです!
要約
結論として、
- あらゆる種類のデータに対して可逆的なJSONインターフェースを持つことが重要(または戦略的)であるならば、この提案は許可されるでしょう。
- そうでない場合は、エコシステムに掲載されている、この形式をpandas DataFrameとの間で読み書きするサードパーティパッケージを検討すべきです。
コアチームの決定
投票は9月11日から9月26日まで行われました。
- 最終的な集計は、承認0、棄権5、不承認7でした。定足数は満たされました。PDEPは否決されました。
不承認コメント :
- 1 提案されているJSON NTV形式の新規性を考慮すると、(PDEPに記載されているように)「そうでない場合は、エコシステムに掲載されている、この形式をpandas DataFrameとの間で読み書きするサードパーティパッケージを検討すべき」を支持します。
- 2 -1- と同じ理由で、これは現時点ではサードパーティパッケージであるべきです。
- 3 成熟度が十分でなく、市場規模も不明確です。
- 4 PDEPで述べたのと同じ理由です。「この(JSON-NTV形式は)pandas内で実装される一般的な形式であるという基準を満たしていないと思います。」
- 5 -4- に同意します。
- 6 他のコア開発者からの回答に同意します。既存のjsonインターフェースに関する作業は非常に価値があると思います。提起された元の問題の多くは、単なるバグ修正/既存機能の拡張です。一からやり直すのは、移行の労力に見合わない可能性が高いです。とはいえ、もしコミュニティで十分にサポートされている形式であれば、将来的に再検討することができます(明らかにjsonは十分にサポートされていますが、ここで詳述されている実際の仕様は新しすぎるか、標準として受け入れられていません)。
- 7 より包括的なJSON形式を持つことは価値があると考えますが、新しい形式をpandasの一部にすることは、より広いコミュニティでまだ検討中の標準を暗黙的に承認することを意味します。
決定:
ntv-pandasパッケージをエコシステムに追加する- このPDEPを後日、例えば半年から1年後に再検討する(インターネットドラフトJSON semantic format (JSON-NTV)の進化とntv-pandasの使用状況に基づき)。
タイムライン
該当なし
PDEP履歴
- 2023年6月16日:最初の草案
- 2023年7月22日:F.A.Q.を追加
- 2023年9月6日:Table Schema拡張を追加
- 10月1日:コアチームの決定を追加