$30 off During Our Annual Pro Sale. View Details »

データに関する堅牢性と可読性を向上させるpydanticとpanderaの活用方法の提案

 データに関する堅牢性と可読性を向上させるpydanticとpanderaの活用方法の提案

Daiki Katsuragawa

October 15, 2022
Tweet

More Decks by Daiki Katsuragawa

Other Decks in Programming

Transcript

  1. データに関する堅牢性と可読性を向上させる pydanticとpanderaの活用方法の提案 (PyCon JP 2022) 桂川大輝

  2. 自己紹介 • 名前:桂川 大輝(GitHub:daikikatsuragawa[1]) • Pythonの使用用途:開発、分析、研究 2 [1] daikikatsuragawa (Daiki

    Katsuragawa)(https://github.com/daikikatsuragawa)
  3. 目次 • 背景:データに関する問題 • 前提知識:型ヒント • 提案①:構造で表現されるデータのスキーマをpydanticで定義 • 提案②:データフレームのスキーマをpanderaで定義 •

    提案③:pydanticとpanderaを併用 • 付録:pydanticとpanderaの導入前に把握・検証しておくべきリスク • まとめ 3
  4. 目次 • 背景:データに関する問題 • 前提知識:型ヒント • 提案①:構造で表現されるデータのスキーマをpydanticで定義 • 提案②:データフレームのスキーマをpanderaで定義 •

    提案③:pydanticとpanderaを併用 • 付録:pydanticとpanderaの導入前に把握・検証しておくべきリスク • まとめ 4
  5. Pythonによる開発とデータ • 多くの開発におけるデータ ◦ データの管理 ◦ データの処理 • Pythonによる開発におけるデータ ◦

    データ分析 ◦ 機械学習(データからルールやパターンを発見) 5 Pythonによる開発ではデータの扱いの幅が広い
  6. 機械学習を使った処理の例 1. データ収集 ◦ ドメインに基づくデータを収集 2. 前処理 ◦ 収集したデータを任意の処理に基づき学習用に変換 3.

    学習 ◦ 前処理済みデータを学習(モデルの作成) 4. 予測 ◦ 学習済みモデルにより予測 6
  7. 機械学習を使った処理の例〜データに関する問題〜 1. データ収集 ◦ ドメインに基づくデータを収集 2. 前処理 ◦ 収集したデータを任意の処理に基づき学習用に変換 3.

    学習 ◦ 前処理済みデータを学習(モデルの作成) 4. 予測 ◦ 学習済みモデルにより予測 7 様々な理由により 期待しないデータを 収集してしまう可能性 (例:年齢が-1)
  8. 機械学習を使った処理の例〜データに関する問題〜 1. データ収集 ◦ ドメインに基づくデータを収集 2. 前処理 ◦ 収集したデータを任意の処理に基づき学習用に変換 3.

    学習 ◦ 前処理済みデータを学習(モデルの作成) 4. 予測 ◦ 学習済みモデルにより予測 8 防ぐことができれば問題ないが、 防げなかった場合… 後の処理に影響し、本来もたらす 価値を見出せない (場合によっては不利益も…)
  9. 機械学習を使った処理の例〜データに関する問題〜 1. データ収集 ◦ ドメインに基づくデータを収集 2. 前処理 ◦ 収集したデータを任意の処理に基づき学習用に変換 3.

    学習 ◦ 前処理済みデータを学習(モデルの作成) 4. 予測 ◦ 学習済みモデルにより予測 9 期待しない前処理を 実施してしまう可能性 (例:重要な指標の計算の誤り)
  10. 機械学習を使った処理の例〜データに関する問題〜 1. データ収集 ◦ ドメインに基づくデータを収集 2. 前処理 ◦ 収集したデータを任意の処理に基づき学習用に変換 3.

    学習 ◦ 前処理済みデータを学習(モデルの作成) 4. 予測 ◦ 学習済みモデルにより予測 10 防ぐことができれば問題ないが、 防げなかった場合… 後の処理に影響し、本来もたらす 価値を見出せない (場合によっては不利益も…)
  11. 機械学習を使った処理の例〜データに関する問題〜 1. データ収集 ◦ ドメインに基づくデータを収集 2. 前処理 ◦ 収集したデータを任意の処理に基づき学習用に変換 3.

    学習 ◦ 前処理済みデータを学習(モデルの作成) 4. 予測 ◦ 学習済みモデルにより予測 11 問題:すべてのデータが期待する内容・状態とは限らない
  12. データに関する理想と現実 12 理想 すべてのデータが期待する内容・状態 現実 期待しない内容・状態のデータが存在

  13. データに関する理想と現実と問題 13 理想 すべてのデータが期待する内容・状態 現実 期待しない内容・状態のデータが存在 問題 (ギャップ) すべてのデータが期待する内容・状態とは限らない

  14. データに関する問題 14 解消したい 問題 すべてのデータが期待する内容・状態とは限らない • データに関する堅牢性が低い • データに関する可読性が低い

  15. データに関する堅牢性が低い • 期待しないデータ(型)の格納を許すコード • 期待しないデータ(値)の格納を許すコード 15 probability = 0.5 #

    float型の0~1の値を期待(OK) probability = 50 # float型の0~100の値を期待(NG) number = 1 # int型の値を期待(OK) number = "文字列" # int型の値を期待(NG) 堅牢性の向上が必要(データのバリデーションの実装など)
  16. データに関する可読性が低い • コードからデータの仕様の理解が困難 • • 構造を表現するデータやデータフレームの仕様の理解はより困難 16 可読性の向上が必要(データの仕様の理解を可能にするコードなど) probability #

    float型の0~1の値を期待?/int型の0~100の値を期待? df # データフレーム?/列数は?/各列の期待する型は?/各列の期待する値は?
  17. データに関する問題と課題 17 解消したい 問題 すべてのデータが期待する内容・状態とは限らない • データに関する堅牢性が低い • データに関する可読性が低い 解決したい

    課題 データに関する堅牢性と可読性の向上 データに関する堅牢性と可読性の向上が必要
  18. データに関する課題と打ち手 18 解決したい 課題 データに関する堅牢性と可読性の向上 打ち手 仕組みの導入(例:ライブラリ) データに関する堅牢性と可読性の向上のためのライブラリの導入を検討

  19. データに関する堅牢性と可読性を向上させるための提案 • 構造で表現されるデータのスキーマをpydanticで定義 ◦ pydantic(ライブラリ): スキーマの定義に基づき構造で表現されるデータをバリデーション • データフレームのスキーマをpanderaで定義 ◦ pandera(ライブラリ):

    スキーマの定義に基づきデータフレームをバリデーション • pydanticとpanderaを併用 19 本発表はpydanticとpanderaの活用方法の提案
  20. データに関する堅牢性と可読性を向上させるための提案 • 構造で表現されるデータのスキーマをpydanticで定義 ◦ pydantic(ライブラリ): スキーマの定義に基づき構造で表現されるデータをバリデーション • データフレームのスキーマをpanderaで定義 ◦ pandera(ライブラリ):

    スキーマの定義に基づきデータフレームをバリデーション • pydanticとpanderaを併用 20 前提知識としてpydanticとpanderaの理解に必要な型ヒントを説明
  21. 目次 • 背景:データに関する問題 • 前提知識:型ヒント • 提案①:構造で表現されるデータのスキーマをpydanticで定義 • 提案②:データフレームのスキーマをpanderaで定義 •

    提案③:pydanticとpanderaを併用 • 付録:pydanticとpanderaの導入前に把握・検証しておくべきリスク • まとめ 21
  22. 型ヒントとは? • 型ヒント(Type Hints[2]) ◦ 「変数」、「関数の引数」や「関数の戻り値」の定義に 型のヒントを付与するという記法 • 型ヒントの振る舞い ◦

    実行時に型のチェックはしない(誤りが存在しても動作) ◦ ツール(例:mypy[3])と組み合わせて静的チェックを実現 22 [2] PEP 484 – Type Hints | peps.Python.org(https://peps.Python.org/pep-0484/) [3] mypy - Optional Static Typing for Python(http://www.mypy-lang.org/) コードの可読性の向上 ツールと組み合わせることで堅牢性の向上 name: str = "パイソン 太郎"
  23. 型ヒントの記述方法① • 変数:直後に「:」と型を記述 • 関数の引数:各引数の直後に「:」と型を記述 • 関数の戻り値:「:」の直前に「->」と型を記述 23 name: str

    = "パイソン 太郎" def divide(numerator: int, denominator: int) -> float: return numerator / denominator
  24. 型ヒントの記述方法② • 辞書型(Dict)、リスト型(List)などの要素の型の指定 • 複数の型(Union)の指定 24 from typing import Dict

    user_and_age: Dict[str, int] = {'パイソン 太郎': 20} from typing import Union str_or_int: Union[str, int] = 0 # or パイソン 太郎"
  25. 型ヒントの記述方法③ • 必須ではない(Optional)という指定 • 任意である(Any)という指定 25 from typing import Optional

    optional_int: Optional[int] = None # or 0 from typing import Any any: Any = 0 # or "パイソン 太郎", {"パイソン 太郎": 20} ...
  26. 型ヒントの記述方法④ • 存在しない(None)という指定 26 from typing import Any def return_none(input:

    Any) -> None: pass
  27. 型ヒントの記述方法⑤ • 自作のクラスを指定 27 class SampleClass: pass sample_class: SampleClass =

    SampleClass() def return_input(sample_class: SampleClass) -> SampleClass: return sample_class
  28. 型ヒント〜まとめ〜 • 型ヒント(Type Hints) ◦ 「変数」、「関数の引数」や「関数の戻り値」の定義に 型のヒントを付与するという記法 • 型ヒントの振る舞い ◦

    実行時に型のチェックはしない(誤りが存在しても動作) ◦ ツール(例:mypy)と組み合わせて静的チェックを実現 28 可読性と堅牢性の向上に期待
  29. 型ヒント〜まとめ〜 • 型ヒント(Type Hints) ◦ 「変数」、「関数の引数」や「関数の戻り値」の定義に 型のヒントを付与するという記法 • 型ヒントの振る舞い ◦

    実行時に型のチェックはしない(誤りが存在しても動作) ◦ ツール(例:mypy)と組み合わせて静的チェックを実現 29 型ヒントに基づいて可読性と堅牢性を向上させる pydanticとpanderaを説明
  30. 目次 • 背景:データに関する問題 • 前提知識:型ヒント • 提案①:構造で表現されるデータのスキーマをpydanticで定義 • 提案②:データフレームのスキーマをpanderaで定義 •

    提案③:pydanticとpanderaを併用 • 付録:pydanticとpanderaの導入前に把握・検証しておくべきリスク • まとめ 30
  31. 複数の部品によって構成されるシステムを開発していますか? • 多くのシステムは複数の部品によって構成 ◦ 部品:モジュール・クラス・メソッド・外部のAPIなど • 各部品が役割と責任を持ち連携 ◦ 各部品の入出力を把握しておけばシステムの全ての把握は不要 ◦

    入出力:int、str、JSON(構造) 31 部品Y 部品Z JSON JSON
  32. 堅牢性が低い:期待しないデータを格納してしまう • 期待しないデータのやり取りが発生 32 対応しないと… 部品Y 部品Z JSON 人に関するデータを 格納したJSONを

    渡します。 {name: ”パイソン 太郎” , age: -1} ドメイン的に ありえないデータが来た
  33. 可読性が低い:コードからデータの仕様を読み取れない • 仕様がわからないデータの扱いが困難 • 期待しないデータか否かの判断が困難 33 ???のデータを 格納したJSONを 渡します。 (期待しないデータであ

    ることに気がつかない) 部品Y 部品Z JSON {???: ???, ???:???, …} 何が格納されている?
  34. 構造で表現されるデータのスキーマをpydanticで定義 • pydantic[4] ◦ 定義したスキーマに基づき構造で表現されるデータを バリデーションするライブラリ ◦ 辞書型・JSONとのシリアライズ/デシリアライズも可能(入出力に有用) ◦ GitHubのスター:11.3k[5](2022/10/15時点)

    ◦ ライセンス:MIT License[6] 34 [4] pydantic(https://pydantic-docs.helpmanual.io/) [5] pydantic/pydantic: Data parsing and validation using Python type hints(https://github.com/pydantic/pydantic) [6] pydantic/LICENSE at master · samuelcolvin/pydantic(https://github.com/samuelcolvin/pydantic/blob/master/LICENSE) pip install pydantic
  35. データに関する堅牢性と可読性を向上させるpydantic • 堅牢性の向上 ◦ スキーマの定義に基づくデータのみが存在(バリデーション) • 可読性の向上 ◦ スキーマの定義によるデータの仕様の把握が可能 35

  36. pydanticの利用例〜スキーマの定義とバリデーション〜 36 from pydantic import BaseModel, Field class User(BaseModel): name:

    str age: int = Field(ge=20) external_data = { 'name': 'パイソン 太郎', 'age': 20 } user = User.parse_obj(external_data) 型、有効範囲の定義 デシリアライズ データの仕様の 読み取りが可能 (例:ageは20以上) 定義を満たす インスタンスの生成
  37. pydanticの利用例〜スキーマの定義とバリデーション(エラー)〜 37 from pydantic import BaseModel, Field class User(BaseModel): name:

    str age: int = Field(ge=20) external_data = { 'name': 'パイソン 太郎', 'age': 19 } user = User.parse_obj(external_data) 有効範囲外の値 ValidationError
  38. pydanticの利用例〜バリデーション(エラー)〜 38 --------------------------------------------------------------------------- ValidationError Traceback (most recent call last) (省略)

    ValidationError: 1 validation error for User age ensure this value is greater than or equal to 20 (type=value_error.number.not_ge; limit_value=20) エラーの詳細を確認可能 (例:ageの20以上という定義を満たしていない)
  39. pydanticの利用例〜定義したスキーマを引数とする関数〜 39 from pydantic import validate_arguments @validate_arguments def input_user(user :

    User) -> None: pass external_data = { 'name': 'パイソン 太郎', 'age': 20 } input_user(external_data) 引数のバリデーションを 実行するデコレーター pydanticで定義した クラスも引数として指定
  40. pydanticの利用例〜定義したスキーマを引数とする関数(エラー)〜 40 from pydantic import validate_arguments @validate_arguments def input_user(user :

    User) -> None: pass external_data = { 'name': 'パイソン 太郎', 'age': 19 } input_user(external_data) 有効範囲外の値 ValidationError
  41. pydanticの利用例〜定義したスキーマを返り値とする関数〜 41 def output_user() -> User: external_data = { 'name':

    'パイソン 太郎', 'age': 20 } return User.parse_obj(external_data) output_user()
  42. pydanticの利用例〜定義したスキーマを返り値とする関数(エラー)〜 42 def output_user() -> User: external_data = { 'name':

    'パイソン 太郎', 'age': 19 } return User.parse_obj(external_data) output_user() 有効範囲外の値 ValidationError
  43. pydanticの利用例〜より詳細なスキーマの定義〜 43 from pydantic import BaseModel, Field, validator import unicodedata

    class User(BaseModel): id: int name: str # 半角空白を含む(※前後以外) age: int = Field(ge=20) @validator("name") def check_contain_space(cls, v): if " " not in v.strip(): # 前後の半角空白を無視 raise ValueError("ensure this value contains spaces") return v.strip() # 前後の半角空白を削除 デコレーターによる詳細なスキーマの定義 (例:半角空白を含むか否かを判定)
  44. スキーマの定義に基づくデータのみが存在(バリデーション) 44 部品Y 部品Z JSON pydanticによる堅牢性の向上 スキーマを定義した データのみを出力 (バリデーション) スキーマを定義した

    データのみを入力 (バリデーション) スキーマを定義した データのみが存在
  45. スキーマの定義によるデータの仕様の把握が可能 45 from pydantic import BaseModel, Field class User(BaseModel): name:

    str age: int = Field(ge=20) 型、有効範囲の定義 データの仕様の 読み取りが可能 (例:ageは20以上) pydanticによる可読性の向上
  46. 構造で表現されるデータのスキーマをpydanticで定義〜まとめ〜 • 複数の部品によって構成されるシステムの開発 ◦ 各部品(モジュール・クラス・メソッドなど)が役割と責任を持ち連携 ◦ 堅牢性が低い:期待しないデータを格納してしまう ◦ 可読性が低い:コードからデータの仕様を読み取れない •

    pydantic ◦ 定義したスキーマに基づき構造で表現されるデータを バリデーションするライブラリ ◦ 堅牢性の向上:スキーマの定義に基づくデータのみが存在(バリデーション) ◦ 可読性の向上:スキーマの定義によるデータの仕様の把握が可能 46 pydanticによるデータに関する堅牢性と可読性の向上
  47. 目次 • 背景:データに関する問題 • 前提知識:型ヒント • 提案①:構造で表現されるデータのスキーマをpydanticで定義 • 提案②:データフレームのスキーマをpanderaで定義 •

    提案③:pydanticとpanderaを併用 • 付録:pydanticとpanderaの導入前に把握・検証しておくべきリスク • まとめ 47
  48. データフレームを使っていますか? • データフレーム(pandas.DataFrame[7]) ◦ 表型式のデータの取り込み、加工、集計、分析に利用(例:機械学習) ◦ 例:アヤメ(iris)の特徴と種類(scikit-learn[8]より) 48 [7] pandas

    - Python Data Analysis Library (https://pandas.pydata.org/) [8] scikit-learn: machine learning in Python — scikit-learn 1.1.1 documentation (https://scikit-learn.org/stable/) sepal_length sepal_width petal_length petal_width target 0 5.1 3.5 1.4 0.2 0 1 4.9 3.0 1.4 0.2 0 2 4.7 3.2 1.3 0.2 0 3 4.6 3.1 1.5 0.2 0 4 5.0 3.6 1.4 0.2 0
  49. 堅牢性が低い:期待しないデータを格納してしまう 49 sepal_length sepal_width petal_length petal_width target 146 6.3 2.5

    5.00 1.9 2 147 6.5 3.0 5.20 2.0 2 148 6.2 3.4 5.40 2.3 2 149 5.9 3.0 5.10 1.8 2 150 ◯△□ 3.0 4.35 1.3 3 数値を期待しているが… 文字列が格納されている 0/1/2を期待しているが… 3が格納されている
  50. 可読性が低い:コードからデータの仕様を読み取れない 50 import pandas as pd from sklearn.datasets import load_iris

    data = load_iris() iris = pd.DataFrame(data.data, columns=data.feature_names) iris["target"] = data.target iris.head() irisにはどんなデータが 格納されている?
  51. データフレームのスキーマをpanderaで定義 • pandera[9] ◦ 定義したスキーマに基づきデータフレームをバリデーションするライブラリ ◦ GitHubのスター:1.7k[10](2022/10/15時点) ◦ ライセンス:MIT License[11]

    51 [9] pandera (https://pandera.readthedocs.io/en/stable/) [10] unionai-oss/pandera: A light-weight, flexible, and expressive statistical data testing library (https://github.com/unionai-oss/pandera) [11] pandera/LICENSE.txt at master · unionai-oss/pandera (https://github.com/unionai-oss/pandera/blob/master/LICENSE.txt) pip install pandera
  52. データに関する堅牢性と可読性を向上させるpandera • 堅牢性の向上 ◦ スキーマの定義に基づくデータのみが存在(バリデーション) • 可読性の向上 ◦ スキーマの定義によるデータの仕様の把握が可能 ※2種存在する記述方法より“SchemaModel”を説明

    52
  53. panderaの利用例〜アヤメ(iris)のデータセットの準備〜 53 import pandas as pd from sklearn.datasets import load_iris

    data = load_iris() iris = pd.DataFrame(data.data, columns=data.feature_names) iris["target"] = data.target
  54. panderaの利用例〜アヤメ(iris)のデータセットの準備〜 54 iris = iris.rename( columns={ "sepal length (cm)": "sepal_length",

    "sepal width (cm)": "sepal_width", "petal length (cm)": "petal_length", "petal width (cm)": "petal_width", } ) 説明を簡単に するために改名
  55. panderaの利用例〜データセットの確認①〜 55 iris.head() 0/1/2(カテゴリ) 現実的な数値 sepal_length sepal_width petal_length petal_width target

    0 5.1 3.5 1.4 0.2 0 1 4.9 3.0 1.4 0.2 0 2 4.7 3.2 1.3 0.2 0 3 4.6 3.1 1.5 0.2 0 4 5.0 3.6 1.4 0.2 0
  56. panderaの利用例〜データセットの確認②〜 56 iris.describe() sepal_length sepal_width petal_length petal_width target count 150.000000

    150.000000 150.000000 150.000000 150.000000 mean 5.843333 3.057333 3.758000 1.199333 1.000000 std 0828066 0.435866 1.765298 0.762238 0.819232 min 4.300000 2.000000 1.000000 0.100000 0.000000 25% 5.100000 2.800000 1.600000 0.300000 0.000000 50% 5.800000 3.000000 4.350000 1.300000 1.000000 75% 6.400000 3.300000 5.100000 1.800000 2.000000 max 7.900000 4.400000 6.900000 2.500000 2.000000
  57. panderaの利用例〜スキーマの定義〜 57 import pandera as pa from pandera.typing import Series

    class IrisSchema(pa.SchemaModel): sepal_length: Series[float] = pa.Field(gt=0, le=8) sepal_width: Series[float] = pa.Field(gt=0, le=5) petal_length: Series[float] = pa.Field(gt=0, le=7) petal_width: Series[float] = pa.Field(gt=0, le=3) target: Series[int] = pa.Field(isin=[0, 1, 2]) 0/1/2(カテゴリ) 現実的な数値
  58. panderaの利用例〜バリデーション〜 58 iris = IrisSchema.validate(iris) iris.head() sepal_length sepal_width petal_length petal_width

    target 0 5.1 3.5 1.4 0.2 0 1 4.9 3.0 1.4 0.2 0 2 4.7 3.2 1.3 0.2 0 3 4.6 3.1 1.5 0.2 0 4 5.0 3.6 1.4 0.2 0
  59. panderaの利用例〜期待しないレコードの追加〜 59 invalid_record = { "sepal_length": 5.8, "sepal_width": 3.0, "petal_length":

    4.35, "petal_width": 1.3, "target": 3, # invalid value } invalid_iris = iris.append(invalid_record, ignore_index=True) invalid_iris["target"] = invalid_iris["target"].astype(int)
  60. panderaの利用例〜期待しないレコードの確認〜 60 invalid_iris.tail() sepal_length sepal_width petal_length petal_width target 146 6.3

    2.5 5.00 1.9 2 147 6.5 3.0 5.20 2.0 2 148 6.2 3.4 5.40 2.3 2 149 5.9 3.0 5.10 1.8 2 150 5.8 3.0 4.35 1.3 3
  61. panderaの利用例〜バリデーション(エラー)〜 61 invalid_iris = IrisSchema.validate(invalid_iris) --------------------------------------------------------------------------- SchemaError Traceback (most recent

    call last) (省略) SchemaError: <Schema Column(name=target, type=DataType(int64))> failed element-wise validator 0: <Check isin: isin({0, 1, 2})> failure cases: index failure_case 0 150 3 indexが150のレコードでエラー SchemaError
  62. スキーマの定義に基づくデータのみが存在(バリデーション) 62 panderaによる堅牢性の向上 sepal_length sepal_width petal_length petal_width target 146 6.3

    2.5 5.00 1.9 2 147 6.5 3.0 5.20 2.0 2 148 6.2 3.4 5.40 2.3 2 149 5.9 3.0 5.10 1.8 2 150 ◯△□ 3.0 4.35 1.3 3 SchemaError
  63. スキーマの定義によるデータの仕様の把握が可能 63 import pandera as pa from pandera.typing import Series

    class IrisSchema(pa.SchemaModel): sepal_length: Series[float] = pa.Field(gt=0, le=8) sepal_width: Series[float] = pa.Field(gt=0, le=5) petal_length: Series[float] = pa.Field(gt=0, le=7) petal_width: Series[float] = pa.Field(gt=0, le=3) target: Series[int] = pa.Field(isin=[0, 1, 2]) 0/1/2(カテゴリ) 現実的な数値 panderaによる可読性の向上
  64. データフレームのスキーマをpanderaで定義〜まとめ〜 • データフレーム(pandas.DataFrame) ◦ 表形式のデータの取り込み、加工、集計、分析に利用(機械学習などで活用) ◦ 堅牢性が低い:期待しないデータを格納してしまう ◦ 可読性が低い:コードからデータの仕様を読み取れない •

    pandera ◦ 定義したスキーマに基づきデータフレームをバリデーションするライブラリ ◦ 堅牢性の向上:スキーマの定義に基づくデータのみが存在(バリデーション) ◦ 可読性の向上:スキーマの定義によるデータの仕様の把握が可能 64 panderaによるデータに関する堅牢性と可読性の向上
  65. 目次 • 背景:データに関する問題 • 前提知識:型ヒント • 提案①:構造で表現されるデータのスキーマをpydanticで定義 • 提案②:データフレームのスキーマをpanderaで定義 •

    提案③:pydanticとpanderaを併用 • 付録:pydanticとpanderaの導入前に把握・検証しておくべきリスク • まとめ 65
  66. pydanticとpanderaを併用 • 類似した記述方法 • 組み合わせた利用 66

  67. pydanticとpandera(SchemaModel)の類似した記述方法 67 # pydantic # Userのスキーマ from pydantic import BaseModel,

    Field class User(BaseModel): name: str age: int = Field(ge=20) # pandera # Userをレコードとするデータフレームのスキーマ import pandera as pa from pandera.typing import Series class UserSchema(pa.SchemaModel): name: Series[str] age: Series[int] = pa.Field(ge=20)
  68. pydanticとpandera(SchemaModel)の類似した記述方法(差分) 68 # pydantic # Userのスキーマ from pydantic import BaseModel,

    Field class User(BaseModel): name: str age: int = Field(ge=20) # pandera # Userをレコードとするデータフレームのスキーマ import pandera as pa from pandera.typing import Series class UserSchema(pa.SchemaModel): name: Series[str] age: Series[int] = pa.Field(ge=20) pydanticを理解していれば pandera(SchemaModel)の理解は容易 pandera(SchemaModel)を理解していれば pydanticの理解は容易
  69. pydanticとpandera(SchemaModel)の類似した記述方法(差分) 69 # pydantic # Userのスキーマ from pydantic import BaseModel,

    Field class User(BaseModel): name: str age: int = Field(ge=20) # pandera # Userをレコードとするデータフレームのスキーマ import pandera as pa from pandera.typing import Series class UserSchema(pa.SchemaModel): name: Series[str] age: Series[int] = pa.Field(ge=20) pydanticと併用するpanderaの利用方法は“SchemaModel”
  70. pydanticとpanderaを組み合わせた利用 70 import pandera as pa from pandera.engines.pandas_engine import pydanticModel

    # pandera 0.10.0~ from pandera.typing import Series from pydantic import BaseModel, Field class User(BaseModel): name: str age: int = Field(ge=20) class UserSchema(pa.SchemaModel): class Config: dtype = pydanticModel(User) coerce = True Userスキーマ(pydanticにより定義)に従う レコードの集合となるデータフレームの スキーマ(panderaにより定義)
  71. pydanticとpanderaを併用〜まとめ〜 • 類似した記述方法 ◦ 記述方法は対応しており差分は少ない ◦ 一方に慣れていれば他方の導入も容易 ◦ pydanticと併用するpanderaの利用方法は“SchemaModel” •

    組み合わせた利用 ◦ スキーマ(pydanticにより定義)に従うレコードの集合となる データフレームのスキーマ(panderaにより定義)の実現 71 両方を活用できる場合にpydanticとpanderaを併用
  72. データに関する堅牢性と可読性を向上させるための3つの提案 • 提案①:構造で表現されるデータのスキーマをpydanticで定義 • 提案②:データフレームのスキーマをpanderaで定義 • 提案③:pydanticとpanderaを併用 72 3つの提案をpydanticとpanderaの導入の意思決定の参考に!

  73. 目次 • 背景:データに関する問題 • 前提知識:型ヒント • 提案①:構造で表現されるデータのスキーマをpydanticで定義 • 提案②:データフレームのスキーマをpanderaで定義 •

    提案③:pydanticとpanderaを併用 • 付録:pydanticとpanderaの導入前に把握・検証しておくべきリスク • まとめ 73
  74. pydanticとpanderaの導入に伴い発生するリスク • 導入に伴い発生するリスクが存在 ◦ 導入した後に発生する不具合 ◦ 開発プロセスにおけるコスト • リスクの把握や検証をした上での意思決定が大事 74

    pydanticとpanderaの導入前にリスクの把握や検証が必要
  75. pydanticとpanderaの導入前に把握・検証しておくべきリスクの例 • 学習コスト ◦ 開発者の学習コストが確保できるか? • 処理時間 ◦ バリデーションによって増加される処理時間は許容範囲に収まるか? ◦

    成果物がもたらす価値にも影響する可能性 • ライブラリの容量 ◦ 実行環境においてインストールするライブラリの容量が確保できるか? 75 pydanticとpanderaがもたらす価値とリスクを比較して意思決定
  76. 目次 • 背景:データに関する問題 • 前提知識:型ヒント • 提案①:構造で表現されるデータのスキーマをpydanticで定義 • 提案②:データフレームのスキーマをpanderaで定義 •

    提案③:pydanticとpanderaを併用 • 付録:pydanticとpanderaの導入前に把握・検証しておくべきリスク • まとめ 76
  77. まとめ • データに関する問題(解消したい問題) ◦ すべてのデータが期待する内容・状態とは限らない • 解決したい課題 ◦ データに関する堅牢性と可読性の向上 •

    提案①:構造で表現されるデータのスキーマをpydanticで定義 • 提案②:データフレームのスキーマをpanderaで定義 • 提案③:pydanticとpanderaを併用 77