PDEP-12: コンパクトで可逆的なJSONインターフェース
- 作成日: 2023年6月16日
- ステータス: 却下
- 議論: #53252 #55038
- 作成者: Philippe THOMY
- リビジョン: 3
概要
- 要約
- 問題の説明
- 機能の説明
- スコープ
- 動機
- コンパクトで可逆的なJSONインターフェースを持つことがなぜ重要なのか?
- 拡張型を考慮することは適切か?
- これはpandasのみに役立つのか?
- 説明
- データ型指定
- TableSchemaとpandasの対応
- JSON形式
- 変換
- 使用法と影響
- 使用法
- 互換性
- pandasフレームワークへの影響
- 実行するリスク / 実行しないリスク
- 実装
- モジュール
- 実装オプション
- よくある質問
- まとめ
- コアチームの決定
- タイムライン
- PDEP履歴
要約
問題の説明
現在のJSONインターフェースでは、dtype
と「Python型」は明示的に考慮されていません。
そのため、JSONインターフェースは常に可逆的ではなく、dtype
の考慮に関して不整合があります。
もう1つの結果として、orient="table"
オプションにおけるTable Schema仕様の部分的な適用があります(定義されている24のTable Schemaデータ型のうち6つが考慮されています)。
JSONインターフェースに関するいくつかの問題は、リンクされたノートブックで詳しく説明されています。
機能の説明
シンプルでコンパクト、かつ可逆的なソリューションを実現するために、型の概念を統合したJSON-NTV形式(名前付きおよび型付き値)とその表形式データの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
その他の例は、リンクされたノートブックに記載されています。
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
その他の例は、リンクされたノートブックに記載されています。
スコープ
目的は、提案されたJSONインターフェースをあらゆる種類のデータ、およびorient="table"
オプションまたは新しいオプションorient="ntv"
で利用できるようにすることです。
提案されたインターフェースは、既存のデータと互換性があります。
動機
なぜorient=table
オプションを他のデータ型に拡張するのか?
- Table Schema仕様では24のデータ型が定義されていますが、pandasインターフェースでは6つが考慮されています。
コンパクトで可逆的な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型(文字列ISO8601)です。
CategoricalDtype
とSparseDtype
は、表形式JSON形式に含まれています。object
dtype
はコンテキストによって異なります(以下を参照)。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 type / 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 type
が定義されていない場合:to_json()
を使用します。NTV type
が定義されていて、dtype
がobject
でない場合:to_json()
を使用します。NTV type
が定義されていて、dtype
がobject
である場合: NTV変換を使用します(pandas変換が存在しない場合)。
JSON -> pandas
NTV type
がdtype
と互換性がある場合:read_json()
を使用します。NTV type
がdtype
と互換性がない場合: NTV変換を使用します(pandas変換が存在しない場合)。
使用法と影響
使用法
この提案は、重要な問題に対処しているように思われます。
-
データ交換のための効率的なテキスト形式を持つこと
代替のCSV形式は可逆的ではなく、時代遅れです(最終改訂は2005年)。 現在のCSVツールは標準に準拠していません。
-
pandasオブジェクトで「セマンティック」データを考慮すること
-
完全なTable Schemaインターフェースを持つこと
互換性
インターフェースはNTV型なしで使用できます(既存のデータとの互換性 - 例を参照)。
インターフェースが使用可能な場合、JSONインターフェースに新しいorient
オプションを追加することで、機能の使用は他の機能から分離されます。
pandasフレームワークへの影響
初期段階では、影響は非常に限定的です。
Series
またはDataFrameの列
のname
の変更(機能的な影響なし)- Jsonインターフェースにオプションを追加(例:
orient='ntv'
)し、関連するメソッドを追加(他のメソッドとの機能的な干渉なし)
後の段階では、いくつかの開発が検討される可能性があります。
Series
またはDataFrameの列
のname
の検証- NTV型の「complementary-object-dtype」としての管理
- NTV型に応じた機能拡張
実行するリスク / 実行しないリスク
JSON-NTV形式とJSON-TAB形式は、(まだ)認識されておらず、使用されている形式ではありません。 pandasのリスクは、この関数が使用されないことです(機能的な影響はありません)。
一方、pandasによる早期使用により、pandasの期待とニーズをよりよく考慮し、pandasがサポートする型の進化について考察することができます。
実装
モジュール
NTV用に2つのモジュールが定義されています。
-
json-ntv
このモジュールは、他のモジュールに依存せずにNTVデータを管理します。
-
ntvconnector
これらのモジュールは、オブジェクトとJSONデータ間の変換を管理します。 これらはオブジェクトモジュールに依存しています(例:shapely locationを持つコネクタはshapelyに依存しています)。
JSONインターフェースのpandas統合には、json-ntvモジュールのみをインポートする必要があります。
実装オプション
インターフェースは、NTVコネクタ(SeriesConnector
とDataFrameConnector
)として、および新しいpandas JSONインターフェースorient
オプションとして実装できます。
pandasのいくつかの実装が可能です。
-
外部
この実装では、インターフェースはNTV側でのみ使用できます。 このオプションは、JSONインターフェースのこの進化がpandasにとって有用でも戦略的でもないことを意味します。
-
NTV側
この実装では、インターフェースは両側で使用可能であり、変換はNTV内部で行われます。このオプションは、pandas側への影響を最小限に抑えるものです。
-
pandas側
この実装では、インターフェースは両側で使用可能であり、変換はpandas内部で行われます。このオプションにより、pandasはこの進化を制御し続けることができます。
-
pandas制限付き
この実装では、pandasインターフェースと変換はpandas内部に配置され、オブジェクト以外の
dtype
のみに使用されます。このオプションにより、既存のdtype
と互換性のない型の導入を禁止しながら、コンパクトで可逆的なインターフェースを提供することが可能になります。
よくある質問
Q: orient="table"
では、すでに提案されていることはできないのでしょうか?
A: 原則的には、はい。このオプションは型の概念を考慮しています。
しかし、これは非常に限定的です(ノートブックに追加された例を参照)。
- 型とJSONインターフェース
- JSONインターフェースで型を保持する唯一の方法は、
orient='table'
オプションを使用することです。 - いくつかのdtypeは、JSONテーブルインターフェースでは許可されていません:period、timedelta64、interval
- 許可された型は、JSONテーブルインターフェースで常に保持されるとは限りません。
- 'object' dtypeのデータは、データが文字列の場合にのみ保持されます。
- categorical dtypeの場合、基になるdtypeはJSONインターフェースに含まれません。
- データのコンパクト性
- JSONテーブルインターフェースはコンパクトではありません(ノートブックの例では)サイズはコンパクトフォーマットの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"
フォーマットのみを持つべきです。また、フォーマットを変更する場合、後方互換性の問題もあります。テーブルインターフェースにバグがあることは、新しいインターフェースを追加する理由にはなりません(むしろ、それらのバグを修正する方が良いでしょう)。既存のフォーマットは、型の課題/ラウンドトリップの課題を修正する方法で適応させることはできますか?
A: 2つの追加の備考を追加します。
- Tableschemaで定義されている型は部分的に考慮されています(インターフェースで考慮されていない型の例:string-uri、array、date、time、year、geopoint、string-email)。
read_json()
インターフェースは、次のデータでも機能します:{'simple': [1,2,3] }
(ドキュメントに記載されている内容とは異なります)が、to_json()
でこの単純なJSONを再作成することはできません。
問題はバグ修正に限定されることはできないと考えており、特に、オープンデータソリューションにおいて、廃止されたCSVフォーマットからJSONフォーマットへの段階的な移行に伴い、JSONインターフェースの明確な戦略を定義する必要があります。
述べたように、提案されたソリューションは、現在のインターフェースのいくつかの欠点を addressedし、pandas環境にシンプルに適合できます(他のオプションは、JSONインターフェースはpandasの周辺機能であり、pandasの外部にとどまることができると考えることです)。orient='table'
オプションに関係なく。
それでも、extDtype
の概念を明示的に管理するために、提案されたフォーマットとorient='table'
フォーマットをマージすることは可能です。
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/2年から1年後(インターネットドラフトJSONセマンティックフォーマット(JSON-NTV)の進化とntv-pandasの使用状況に基づいて)再び検討します。
タイムライン
該当なし
PDEP履歴
- 2023年6月16日:初期ドラフト
- 2023年7月22日:FAQを追加
- 2023年9月6日:Table Schema拡張機能を追加
- 10月1日:コアチームの決定を追加