今回は、pandasデータフレームのlocを用いた欠損値の補完についての応用的な使い方を紹介する。

サンプルデータフレームの用意

サンプルとして以下のようなデータフレームを用意した。

単純な売上データをデータフレーム化したものだ。

import pandas as pd
import numpy as np

df = pd.DataFrame([
    ['2019-11-01 00:00:00', 'item_a', 2000],
    ['2019-11-02 00:00:00', 'item_b', np.nan],
    ['2019-11-03 00:00:00', 'item_c', 10000],
    ['2019-11-04 00:00:00', 'item_b', 900],
    ['2019-11-05 00:00:00', 'item_a', 2000],
    ['2019-11-06 00:00:00', 'item_c', 10000],
    ['2019-11-07 00:00:00', 'item_a', np.nan],
    ['2019-11-08 00:00:00', 'item_a', np.nan],
    ['2019-11-09 00:00:00', 'item_c', np.nan],
    ['2019-11-10 00:00:00', 'item_b', 900],
], columns=['purchase_date', 'item_name', 'price'])

#          purchase_date item_name    price
# 0  2019-11-01 00:00:00    item_a   2000.0
# 1  2019-11-02 00:00:00    item_b      NaN
# 2  2019-11-03 00:00:00    item_c  10000.0
# 3  2019-11-04 00:00:00    item_b    900.0
# 4  2019-11-05 00:00:00    item_a   2000.0
# 5  2019-11-06 00:00:00    item_c  10000.0
# 6  2019-11-07 00:00:00    item_a      NaN
# 7  2019-11-08 00:00:00    item_a      NaN
# 8  2019-11-09 00:00:00    item_c      NaN
# 9  2019-11-10 00:00:00    item_b    900.0

このデータフレームの金額情報(price列)にはいくつかの欠損値NaNが含まれている。

今回は、この欠損値を正しい金額で穴埋めする方法を紹介する。

欠損値が含まれている行を調べる

まず、price列に欠損値が含まれている行を調べるため、isnull関数を使って変数に保存しておく。

Trueとなっている行が、金額情報の欠損を表す。

flg_is_null = df['price'].isnull()
# 0    False
# 1     True
# 2    False
# 3    False
# 4    False
# 5    False
# 6     True
# 7     True
# 8     True
# 9    False
# Name: price, dtype: bool

同じ商品で金額が正しく入った行を利用して補完する

少々ややこしいコードではあるが、for文とlocを使って金額が正しく入力されている行を利用して、欠損値を補完していく。

for trg in list(df.loc[flg_is_null, 'item_name'].unique()):
    price = df.loc[(~flg_is_null) & (df['item_name'] == trg), 'price'].max()
    df['price'].loc[(flg_is_null) & (df['item_name'] == trg)] = price
    
#          purchase_date item_name    price
# 0  2019-11-01 00:00:00    item_a   2000.0
# 1  2019-11-02 00:00:00    item_b    900.0
# 2  2019-11-03 00:00:00    item_c  10000.0
# 3  2019-11-04 00:00:00    item_b    900.0
# 4  2019-11-05 00:00:00    item_a   2000.0
# 5  2019-11-06 00:00:00    item_c  10000.0
# 6  2019-11-07 00:00:00    item_a   2000.0
# 7  2019-11-08 00:00:00    item_a   2000.0
# 8  2019-11-09 00:00:00    item_c  10000.0
# 9  2019-11-10 00:00:00    item_b    900.0

データフレームのlocは、任意の条件に合致するデータを抽出する関数だ。

1行目のfor文では、flg_is_nullがTrueの行。
つまり欠損値が含まれている行を抽出し、そのうちitem_nameのみを切り出している。
また、item_nameの重複を排除するようunique関数も併用している。
これで「重複を除く、欠損値が含まれている商品名」を抽出できた。
後はこれをlist関数で配列化し、ループ処理をかけているだけだ。

2行目のlocでは、「~」でTrue/Falseを反転させ、金額が正しく入力されている行を、尚且つ同じ商品名である行を抽出し、その金額を変数priceに保存している。

そして3行目で、欠損値のある行に保存した変数priceを代入し、正しい金額への補完を行っている。

このようにloc関数を使いこなすことで、整合性のない汚いデータをクリーンアップすることができる。