日々精進

新しく学んだことを書き留めていきます

集計はlong formatよりwide formatの方が速い

long formatとwide formatについては以下参照。

www.theanalysisfactor.com

long formatのDataFrameに対して以下のように商品毎の日別売上合計を集計したところ、53秒かかった。

sums: DataFrame = train.groupby(["item_id", "date"])[SALES_COUNT].sum()

これをwide formatに直し、以下のように商品毎の日別売上合計を集計したところ、0.63秒で終わった。

sums = train.groupby("item_id").sum()

グループの数が数個とかだとlong formatでもすぐ終わるけど、item_idが3000ぐらいあったので100倍近く差が出てしまった。 pandas難しい。。

Pandasで最頻値を計算する処理は非常に重い

以下のように、移動平均などを計算しようとしたらすごく時間がかかっていたので速くしようとした時の話。

    agg = sales[SALES_COUNT].astype("float32").shift(shift).rolling(window) \
        .agg(["mean", "max", "min", "std", lambda x: x.mode()[0]]) \
        .reset_index().set_index("seq_idx")
#2.3秒かかった

↑を↓のように書き換え、最頻値を計算しないようにしたら150倍ぐらい速くなった(!)

    agg = sales[SALES_COUNT].astype("float32").shift(shift).rolling(window) \
        .agg(["mean", "max", "min", "std"]) \
        .reset_index().set_index("seq_idx")
#0.015秒かかった

カスタム関数を使うと遅くなると言うが、ここまで違うとは。。 最頻値が必要な場合はDataFrameからndarrayを取り出してnumpyで処理した方が良いかも。

DataFrame.groupbyでcategory型の列を指定すると、データの中に存在しないカテゴリの集計結果も出力される

状況は以下。

df = df.query("store_id == 'CA_1') # store_id はCA_1, CA_2などがある
df.groupby('CA_1').sum() #=> dfにはCA_1しかないのにCA_2の集計結果の行もできてしまう

以下のようにobserved=Trueオプションを指定すると直る。この挙動をデフォルトにすべきでしょ。。

df.groupby('CA_1', observed=True).sum()

参考: stackoverflow.com

pandasでmulti indexになっているときにindexの列で絞り込む

以下のようにget_level_valuesメソッドでindexのうち一つの列を選択してmaskをかけられる。

        mask: Series = self.features.index.get_level_values(1) == pred_date
        self.features.loc[mask, SALES_COUNT] = pred[PRED_SALES_COUNT]

multi indexはほんとは扱いにくいから使わないようにしたい。。

参考:

stackoverflow.com