$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)
    桂川大輝

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  5. Pythonによる開発とデータ
    ● 多くの開発におけるデータ
    ○ データの管理
    ○ データの処理
    ● Pythonによる開発におけるデータ
    ○ データ分析
    ○ 機械学習(データからルールやパターンを発見)
    5
    Pythonによる開発ではデータの扱いの幅が広い

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  11. 機械学習を使った処理の例〜データに関する問題〜
    1. データ収集
    ○ ドメインに基づくデータを収集
    2. 前処理
    ○ 収集したデータを任意の処理に基づき学習用に変換
    3. 学習
    ○ 前処理済みデータを学習(モデルの作成)
    4. 予測
    ○ 学習済みモデルにより予測
    11
    問題:すべてのデータが期待する内容・状態とは限らない

    View Slide

  12. データに関する理想と現実
    12
    理想 すべてのデータが期待する内容・状態
    現実 期待しない内容・状態のデータが存在

    View Slide

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

    View Slide

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

    View Slide

  15. データに関する堅牢性が低い
    ● 期待しないデータ(型)の格納を許すコード
    ● 期待しないデータ(値)の格納を許すコード
    15
    probability = 0.5 # float型の0~1の値を期待(OK)
    probability = 50 # float型の0~100の値を期待(NG)
    number = 1 # int型の値を期待(OK)
    number = "文字列" # int型の値を期待(NG)
    堅牢性の向上が必要(データのバリデーションの実装など)

    View Slide

  16. データに関する可読性が低い
    ● コードからデータの仕様の理解が困難

    ● 構造を表現するデータやデータフレームの仕様の理解はより困難
    16
    可読性の向上が必要(データの仕様の理解を可能にするコードなど)
    probability # float型の0~1の値を期待?/int型の0~100の値を期待?
    df # データフレーム?/列数は?/各列の期待する型は?/各列の期待する値は?

    View Slide

  17. データに関する問題と課題
    17
    解消したい
    問題
    すべてのデータが期待する内容・状態とは限らない
    ● データに関する堅牢性が低い
    ● データに関する可読性が低い
    解決したい
    課題
    データに関する堅牢性と可読性の向上
    データに関する堅牢性と可読性の向上が必要

    View Slide

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

    View Slide

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

    View Slide

  20. データに関する堅牢性と可読性を向上させるための提案
    ● 構造で表現されるデータのスキーマをpydanticで定義
    ○ pydantic(ライブラリ):
    スキーマの定義に基づき構造で表現されるデータをバリデーション
    ● データフレームのスキーマをpanderaで定義
    ○ pandera(ライブラリ):
    スキーマの定義に基づきデータフレームをバリデーション
    ● pydanticとpanderaを併用
    20
    前提知識としてpydanticとpanderaの理解に必要な型ヒントを説明

    View Slide

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

    View Slide

  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 = "パイソン 太郎"

    View Slide

  23. 型ヒントの記述方法①
    ● 変数:直後に「:」と型を記述
    ● 関数の引数:各引数の直後に「:」と型を記述
    ● 関数の戻り値:「:」の直前に「->」と型を記述
    23
    name: str = "パイソン 太郎"
    def divide(numerator: int, denominator: int) -> float:
    return numerator / denominator

    View Slide

  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 パイソン 太郎"

    View Slide

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

    View Slide

  26. 型ヒントの記述方法④
    ● 存在しない(None)という指定
    26
    from typing import Any
    def return_none(input: Any) -> None:
    pass

    View Slide

  27. 型ヒントの記述方法⑤
    ● 自作のクラスを指定
    27
    class SampleClass:
    pass
    sample_class: SampleClass = SampleClass()
    def return_input(sample_class: SampleClass) -> SampleClass:
    return sample_class

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  31. 複数の部品によって構成されるシステムを開発していますか?
    ● 多くのシステムは複数の部品によって構成
    ○ 部品:モジュール・クラス・メソッド・外部のAPIなど
    ● 各部品が役割と責任を持ち連携
    ○ 各部品の入出力を把握しておけばシステムの全ての把握は不要
    ○ 入出力:int、str、JSON(構造)
    31
    部品Y 部品Z
    JSON
    JSON

    View Slide

  32. 堅牢性が低い:期待しないデータを格納してしまう
    ● 期待しないデータのやり取りが発生
    32
    対応しないと…
    部品Y 部品Z
    JSON
    人に関するデータを
    格納したJSONを
    渡します。
    {name: ”パイソン 太郎” , age: -1}
    ドメイン的に
    ありえないデータが来た

    View Slide

  33. 可読性が低い:コードからデータの仕様を読み取れない
    ● 仕様がわからないデータの扱いが困難
    ● 期待しないデータか否かの判断が困難
    33
    ???のデータを
    格納したJSONを
    渡します。
    (期待しないデータであ
    ることに気がつかない)
    部品Y 部品Z
    JSON
    {???: ???, ???:???, …}
    何が格納されている?

    View Slide

  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

    View Slide

  35. データに関する堅牢性と可読性を向上させるpydantic
    ● 堅牢性の向上
    ○ スキーマの定義に基づくデータのみが存在(バリデーション)
    ● 可読性の向上
    ○ スキーマの定義によるデータの仕様の把握が可能
    35

    View Slide

  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以上)
    定義を満たす
    インスタンスの生成

    View Slide

  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

    View Slide

  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以上という定義を満たしていない)

    View Slide

  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で定義した
    クラスも引数として指定

    View Slide

  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

    View Slide

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

    View Slide

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

    View Slide

  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() # 前後の半角空白を削除
    デコレーターによる詳細なスキーマの定義
    (例:半角空白を含むか否かを判定)

    View Slide

  44. スキーマの定義に基づくデータのみが存在(バリデーション)
    44
    部品Y 部品Z
    JSON
    pydanticによる堅牢性の向上
    スキーマを定義した
    データのみを出力
    (バリデーション)
    スキーマを定義した
    データのみを入力
    (バリデーション)
    スキーマを定義した
    データのみが存在

    View Slide

  45. スキーマの定義によるデータの仕様の把握が可能
    45
    from pydantic import BaseModel, Field
    class User(BaseModel):
    name: str
    age: int = Field(ge=20)
    型、有効範囲の定義
    データの仕様の
    読み取りが可能
    (例:ageは20以上)
    pydanticによる可読性の向上

    View Slide

  46. 構造で表現されるデータのスキーマをpydanticで定義〜まとめ〜
    ● 複数の部品によって構成されるシステムの開発
    ○ 各部品(モジュール・クラス・メソッドなど)が役割と責任を持ち連携
    ○ 堅牢性が低い:期待しないデータを格納してしまう
    ○ 可読性が低い:コードからデータの仕様を読み取れない
    ● pydantic
    ○ 定義したスキーマに基づき構造で表現されるデータを
    バリデーションするライブラリ
    ○ 堅牢性の向上:スキーマの定義に基づくデータのみが存在(バリデーション)
    ○ 可読性の向上:スキーマの定義によるデータの仕様の把握が可能
    46
    pydanticによるデータに関する堅牢性と可読性の向上

    View Slide

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

    View Slide

  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

    View Slide

  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が格納されている

    View Slide

  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にはどんなデータが
    格納されている?

    View Slide

  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

    View Slide

  52. データに関する堅牢性と可読性を向上させるpandera
    ● 堅牢性の向上
    ○ スキーマの定義に基づくデータのみが存在(バリデーション)
    ● 可読性の向上
    ○ スキーマの定義によるデータの仕様の把握が可能
    ※2種存在する記述方法より“SchemaModel”を説明
    52

    View Slide

  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

    View Slide

  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",
    }
    )
    説明を簡単に
    するために改名

    View Slide

  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

    View Slide

  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

    View Slide

  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(カテゴリ)
    現実的な数値

    View Slide

  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

    View Slide

  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)

    View Slide

  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

    View Slide

  61. panderaの利用例〜バリデーション(エラー)〜
    61
    invalid_iris = IrisSchema.validate(invalid_iris)
    ---------------------------------------------------------------------------
    SchemaError Traceback (most recent call last)
    (省略)
    SchemaError: failed element-wise validator 0:

    failure cases:
    index failure_case
    0 150 3
    indexが150のレコードでエラー
    SchemaError

    View Slide

  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

    View Slide

  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による可読性の向上

    View Slide

  64. データフレームのスキーマをpanderaで定義〜まとめ〜
    ● データフレーム(pandas.DataFrame)
    ○ 表形式のデータの取り込み、加工、集計、分析に利用(機械学習などで活用)
    ○ 堅牢性が低い:期待しないデータを格納してしまう
    ○ 可読性が低い:コードからデータの仕様を読み取れない
    ● pandera
    ○ 定義したスキーマに基づきデータフレームをバリデーションするライブラリ
    ○ 堅牢性の向上:スキーマの定義に基づくデータのみが存在(バリデーション)
    ○ 可読性の向上:スキーマの定義によるデータの仕様の把握が可能
    64
    panderaによるデータに関する堅牢性と可読性の向上

    View Slide

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

    View Slide

  66. pydanticとpanderaを併用
    ● 類似した記述方法
    ● 組み合わせた利用
    66

    View Slide

  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)

    View Slide

  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の理解は容易

    View Slide

  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”

    View Slide

  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により定義)

    View Slide

  71. pydanticとpanderaを併用〜まとめ〜
    ● 類似した記述方法
    ○ 記述方法は対応しており差分は少ない
    ○ 一方に慣れていれば他方の導入も容易
    ○ pydanticと併用するpanderaの利用方法は“SchemaModel”
    ● 組み合わせた利用
    ○ スキーマ(pydanticにより定義)に従うレコードの集合となる
    データフレームのスキーマ(panderaにより定義)の実現
    71
    両方を活用できる場合にpydanticとpanderaを併用

    View Slide

  72. データに関する堅牢性と可読性を向上させるための3つの提案
    ● 提案①:構造で表現されるデータのスキーマをpydanticで定義
    ● 提案②:データフレームのスキーマをpanderaで定義
    ● 提案③:pydanticとpanderaを併用
    72
    3つの提案をpydanticとpanderaの導入の意思決定の参考に!

    View Slide

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

    View Slide

  74. pydanticとpanderaの導入に伴い発生するリスク
    ● 導入に伴い発生するリスクが存在
    ○ 導入した後に発生する不具合
    ○ 開発プロセスにおけるコスト
    ● リスクの把握や検証をした上での意思決定が大事
    74
    pydanticとpanderaの導入前にリスクの把握や検証が必要

    View Slide

  75. pydanticとpanderaの導入前に把握・検証しておくべきリスクの例
    ● 学習コスト
    ○ 開発者の学習コストが確保できるか?
    ● 処理時間
    ○ バリデーションによって増加される処理時間は許容範囲に収まるか?
    ○ 成果物がもたらす価値にも影響する可能性
    ● ライブラリの容量
    ○ 実行環境においてインストールするライブラリの容量が確保できるか?
    75
    pydanticとpanderaがもたらす価値とリスクを比較して意思決定

    View Slide

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

    View Slide

  77. まとめ
    ● データに関する問題(解消したい問題)
    ○ すべてのデータが期待する内容・状態とは限らない
    ● 解決したい課題
    ○ データに関する堅牢性と可読性の向上
    ● 提案①:構造で表現されるデータのスキーマをpydanticで定義
    ● 提案②:データフレームのスキーマをpanderaで定義
    ● 提案③:pydanticとpanderaを併用
    77

    View Slide