Upgrade to Pro — share decks privately, control downloads, hide ads and more …

メソッドチェーンを使ってDataFrameの可読性と保守性を向上させよう

yuki_uchida
July 18, 2024
320

 メソッドチェーンを使ってDataFrameの可読性と保守性を向上させよう

みんなのPython勉強会#106 [ https://startpython.connpass.com/event/322207/ ] で発表したLT資料です。

yuki_uchida

July 18, 2024
Tweet

More Decks by yuki_uchida

Transcript

  1. 話したいこと1 こういうコード良く書きますよね? df = pd.read_csv("hoge.csv") df = df[df["userId"] == 1]

    df["GB"] = df["MB"] * 1000 df["TB"] = df["GB"] * 1000 df = df.drop("MB") df = df.drop("GB")
  2. 話したいこと1 この書き方の好ましくない点1 df = pd.read_csv("hoge.csv") df = df[df["userId"] == 1]

    df["GB"] = df["MB"] * 1000 df["TB"] = df["GB"] * 1000 df = df.drop("MB") df = df.drop("GB")
  3. 話したいこと1 この書き方の好ましくない点1 df = pd.read_csv("hoge.csv") df = df[df["userId"] == 1]

    df["GB"] = df["MB"] * 1000 df["TB"] = df["GB"] * 1000 df = df.drop("MB") df = df.drop("GB") 「dfという変数、今どうなってる?」
  4. 話したいこと1 この書き方の好ましくない点1 df = pd.read_csv("hoge.csv") df = df[df["userId"] == 1]

    df["GB"] = df["MB"] * 1000 df["TB"] = df["GB"] * 1000 df = df.drop("MB") df = df.drop("GB") 「dfという変数、今どうなってる?」 jupyter notebookなどの場合、複数セルにわ たって同じ変数を操作することが多い
  5. 話したいこと1 この書き方の好ましくない点1 df = pd.read_csv("hoge.csv") df = df[df["userId"] == 1]

    df["GB"] = df["MB"] * 1000 df["TB"] = df["GB"] * 1000 df = df.drop("MB") df = df.drop("GB") 「dfという変数、今どうなってる?」 jupyter notebookなどの場合、複数セルにわ たって同じ変数を操作することが多い 処理に順序性がある(この処理を実行していな いと後続の処理がバグる)場合、とりあえず最 初のセルから再実行する・・・
  6. 話したいこと1 この書き方の好ましくない点1 df = pd.read_csv("hoge.csv") df = df[df["userId"] == 1]

    df["GB"] = df["MB"] * 1000 df["TB"] = df["GB"] * 1000 df = df.drop("MB") df = df.drop("GB") 「dfという変数、今どうなってる?」 jupyter notebookなどの場合、複数セルにわ たって同じ変数を操作することが多い 処理に順序性がある(この処理を実行していな いと後続の処理がバグる)場合、とりあえず最 初のセルから再実行する・・・ ごちゃごちゃ操作していくうちに、最初のセ ルから実行しても動かなくなったりする
  7. 話したいこと1 この書き方の好ましくない点2 df = pd.read_csv("hoge.csv") df_1 = df[df["pattern"] == 1]

    df_1["GB"] = df_1["MB"] * 1000 df_1["TB"] = df_1["GB"] * 1000 df_1_1 = df_1.drop("MB") df_1_2 = df_1_1.drop("GB")
  8. 話したいこと1 この書き方の好ましくない点2 df = pd.read_csv("hoge.csv") df_1 = df[df["pattern"] == 1]

    df_1["GB"] = df_1["MB"] * 1000 df_1["TB"] = df_1["GB"] * 1000 df_1_1 = df_1.drop("MB") df_1_2 = df_1_1.drop("GB") DataFrameを作りまくってメモリを圧迫
  9. 話したいこと1 この書き方の好ましくない点2 df = pd.read_csv("hoge.csv") df_1 = df[df["userId"] == 1].copy()

    df_1["GB"] = df_1["MB"] * 1000 df_1["TB"] = df_1["GB"] * 1000 df_1_1 = df_1.drop("MB") df_1_2 = df_1_1.drop("GB") DataFrameを作りまくってメモリを圧迫
  10. 話したいこと1 この書き方の好ましくない点2 df = pd.read_csv("hoge.csv") df_1 = df[df["userId"] == 1].copy()

    df_1["GB"] = df_1["MB"] * 1000 df_1["TB"] = df_1["GB"] * 1000 df_1_1 = df_1.drop("MB") df_1_2 = df_1_1.drop("GB") DataFrameを作りまくってメモリを圧迫 軽量のデータであれば問題ないが、GB級のデ ータを扱うようになると、この無駄なメモリ 使用に苦しむことになる
  11. 話したいこと2 メソッドチェーンを使ってみよう df = pd.read_csv("hoge.csv") df_1 = df[df["pattern"] == 1]

    df_1["GB"] = df_1["MB"] * 1000 df_1["TB"] = df_1["GB"] * 1000 df_1_1 = df_1.drop("MB") df_1_2 = df_1_1.drop("GB")
  12. 話したいこと2 メソッドチェーンを使ってみよう df = ( pd.read_csv("hoge.csv") .query("pattern == 1") .assign(GB=lambda

    x: x["MB"] * 1000) .assign(TB=lambda x: x["GB"] * 1000) .drop(columns=["MB", "GB"]) ) df = pd.read_csv("hoge.csv") df = df[df["userId"] == 1] df["GB"] = df["MB"] * 1000 df["TB"] = df["GB"] * 1000 df = df.drop("MB") df = df.drop("GB")
  13. 話したいこと2 メソッドチェーンを使ってみよう df = ( pd.read_csv("hoge.csv") .query("userId == 1") .assign(GB=lambda

    x: x["MB"] * 1000) .assign(TB=lambda x: x["GB"] * 1000) .drop(columns=["MB", "GB"]) ) df = pd.read_csv("hoge.csv") df = df[df["userId"] == 1] df["GB"] = df["MB"] * 1000 df["TB"] = df["GB"] * 1000 df = df.drop("MB") df = df.drop("GB")
  14. 話したいこと2 メソッドチェーンの利点 df = ( pd.read_csv("hoge.csv") .query("userId == 1") .assign(GB=lambda

    x: x["MB"] * 1000) .assign(TB=lambda x: x["GB"] * 1000) .drop(columns=["MB", "GB"]) )
  15. 話したいこと2 メソッドチェーンの利点 df = ( pd.read_csv("hoge.csv") .query("userId == 1") .assign(GB=lambda

    x: x["MB"] * 1000) .assign(TB=lambda x: x["GB"] * 1000) .drop(columns=["MB", "GB"]) ) dfという変数の状態を考える必 要がなくなる
  16. 話したいこと2 メソッドチェーンの利点 df = ( pd.read_csv("hoge.csv") .query("userId == 1") .assign(GB=lambda

    x: x["MB"] * 1000) .assign(TB=lambda x: x["GB"] * 1000) .drop(columns=["MB", "GB"]) ) dfという変数の状態を考える必 要がなくなる プログラミング全般に言えるが、 変化する値は少ければ少ないほど バグが起きづらい
  17. 話したいこと2 メソッドチェーンの利点 df = ( pd.read_csv("hoge.csv") .query("userId == 1") .assign(GB=lambda

    x: x["MB"] * 1000) .assign(TB=lambda x: x["GB"] * 1000) .drop(columns=["MB", "GB"]) ) dfという変数の状態を考える必 要がなくなる dfに関わる操作が一塊になり、 変更が容易になる
  18. 話したいこと2 メソッドチェーンの利点 df = ( pd.read_csv("hoge.csv") .query("userId == 1") .assign(GB=lambda

    x: x["MB"] * 1000) .assign(TB=lambda x: x["GB"] * 1000) .drop(columns=["MB", "GB"]) ) dfという変数の状態を考える必 要がなくなる dfに関わる操作が一塊になり、 変更が容易になる 無駄なdataframeが作られない
  19. 話したいこと3 メソッドチェーンの弱点 基本的にはメソッドチェーンを使って書けるなら書いた方が良いと思ってい るが、弱点もある デバッグに慣れが必要 途中経過の確認のために.pipeを繋げて中でprint文を打ったりする データ抽出の速度が遅い(かも) df[df[”hoge”] == 1]

    よりも df.query(“hoge == 1”)の方が5倍くら い遅いこともあった Pythonの関数に頼って抽出する場合にちょっと無駄が多い df[”user”].str.contains(“test”) df.query(“user.str.contains(test)”, engine=”python”)