【解説】データサイエンス100本ノック【問79〜83 回答】
当ページのリンクには広告が含まれています。
- 第79〜83問目を解くために必要な基礎知識
- 第80問目: 欠損レコードの削除
- 第81問目: 数値補完(平均値)
- 第82問目:数値補完(中央値)
- 第83問目: 数値補完(カテゴリごとの中央値)
- まとめ:データサイエンス100本ノック【問79〜83 回答】で欠陥値の扱いを学びました
データサイエンス100本ノックの始め方は、以下の記事を参考にしていただければと思います。
第79〜83問目を解くために必要な基礎知識
問題を解く前に欠損値が存在する場合の補完方法に関する基礎をまとめておきます。
データフレームの中に欠損値が含まれるかもしれないとき、「確認」と「補完」または「削除」を行います。
「補完」には、様々な補完方法が存在します。
例えば、「平均値で補完」だったり「中央値で補完」といったものがあります。
繰り返しになりますが、問題を解いていく前に代表的な手法を簡単なデータフレームを用いて紹介したいと思います。
以下のような欠損値を含むデータフレームを用いて解説します。
1 | import pandas as pd |
1 | product price |
欠損の確認方法
DataFrame, Seriesにおいて、各要素に対して欠損値を確認するには、isnull
メソッドを使用します。
1 | df.isnull() |
1 |
|
上記出力のように、欠損値が存在する箇所がTrue
となります。
欠損レコードの削除方法
欠損がある行や列を全部削除する場合は、dropna
メソッドを使用します。
1 | df.dropna() |
1 | product price |
上記の出力の用にprice
列において欠損があった行は、まるごと削除されていることがわかります。
これを、リストワイズ削除といいます。
欠損の補完方法
続いて補完の方法です。
欠損値にデータを補完する際はfillna
メソッドと主に使用します。
fillna
メソッドは、辞書型で引数を指定することで、カラムごとにデータを補完することができます。
ここでは「平均値」、「中央値」で補完する方法を紹介します。
平均値で補完する方法
欠損値が含まれている箇所を平均値で補完するには、numpy.nanmean
関数を使用します。
ここでは、fillna
メソッドを用いてproduct
カラムにはmelon
、price
には今のprice列に存在する価格である200, 120, 700の平均値を補完したいと思います
1 | df.fillna({'product':'melon', 'price':np.nanmean(df['price'])}) |
1 |
|
上記のように、productにはmelon、そしてpriceには200, 120, 700の平均値である340が補完されています。
中央値で補完する方法
欠損値が含まれている箇所を中央値で補完するには、numpy.nanmedian
関数を使用します。
こちらも同様にfillna
メソッドを用いてproduct
カラムにはmelon, priceには今のprice列に存在する価格である200, 120, 700の中央値を補完したいと思います
1 | df |
1 | product price |
1 | df.fillna({'product':'melon', 'price':np.nanmedian(df['price'])}) |
1 | product price |
上記のように、productにはmelon
、そしてprice
には200, 120, 700の中央値である200が補完されています。
(応用)applyを用いた細かい数値処理と補完
本データフレームにおいて、たとえば欠損値であれば中央値を代入し、それ以外は30%値上げさせる処理をしたい場合を考えましょう。
やり方としては、applyメソッドとnumpy.isnan
関数をを活用することで補完が可能です。
1 |
|
1 | product price |
上記のように、productにはmelonが補完されています。その上でpriceカラムの欠損値には中央値、既に価格が設定されていた値段は3割増しになっています。
欠損値の確認と補完方法の基礎については以上です。
ここまでの知識をもとに問題を解いていきましょう。
第79問目: 欠損列状況の確認
P-079: 商品データフレーム(df_product)の各項目に対し、欠損数を確認せよ。
DataFrame, Seriesでは、各要素に対して欠損値を確認するためには、isnullメソッドを使用します。
実際に本問を解きながら使い方を確認しましょう。
1 | df_product.isnull().sum() |
1 | product_cd 0 |
このように、欠損値を確認するためにはisnullメソッドを使用します。
その上で、各カラムに対して、合計を出す場合sumメソッドを使用することで、欠損値の判定とともに各項目ごとの数を出力できます。
第80問目: 欠損レコードの削除
P-080: 商品データフレーム(df_product)のいずれかの項目に欠損が発生しているレコードを全て削除した新たなdf_product_1を作成せよ。なお、削除前後の件数を表示させ、前設問で確認した件数だけ減少していることも確認すること。
データ欠損のある行や列を全て削除することを、「リストワイズ削除」といいます。
dropnaメソッドを用いることでNaNを含む全ての行を全て取り除けます。
本問を解きながらdropnaメソッドの使い方を学びましょう。
まずは、削除前の件数を出力します。
1 | df_product_1 = df_product.copy() |
1 | 削除前: 10030 |
欠損値を削除しデータの件数を出力します。
1 | df_product_1.dropna(inplace=True) |
1 | 削除語: 10023 |
削除前が10030であるのに対して削除後は10023と件数が減少していることが確認できました。
第81問目: 数値補完(平均値)
P-081: 単価(unit_price)と原価(unit_cost)の欠損値について、それぞれの平均値で補完した新たなdf_product_2を作成せよ。なお、平均値について1円未満は四捨五入とし、0.5については偶数寄せでかまわない。補完実施後、各項目について欠損が生じていないことも確認すること。
欠損値NaNにデータを保管するにはfillnaメソッドを使用します。
引数は辞書型で指定し、カラムごとに代替データを変更することも可能です。
問題を解きながら使い方を学んでいきましょう。
早速平均値で欠損値を補完します。
なお、欠損値が含まれている状態で平均値を求める場合は、numpy.nenmean
関数を使用します。
参考: https://note.nkmk.me/python-numpy-nansum/
四捨五入はnumpy.round関数で行います。SeriesデータにNaNが存在する場合、通常のround関数を用いるとエラーになるので注意しましょう。
参考: https://omathin.com/100knock-66-68/
1 | df_product.head(10) |
1 | product_cd category_major_cd category_medium_cd category_small_cd unit_price unit_cost |
1 | df_product_2 = df_product.fillna({'unit_price':np.round(np.nanmean(df_product['unit_price'])), 'unit_cost':np.round(np.nanmean(df_product['unit_cost']))}) |
1 | product_cd category_major_cd category_medium_cd category_small_cd unit_price unit_cost |
各項目について欠損が生じていないことを確認します。
1 | df_product_2.isnull().sum() |
1 | product_cd 0 |
欠損値が存在していないのでOKです。
第82問目:数値補完(中央値)
P-082: 単価(unit_price)と原価(unit_cost)の欠損値について、それぞれの中央値で補完した新たなdf_product_3を作成せよ。なお、中央値について1円未満は四捨五入とし、0.5については偶数寄せでかまわない。補完実施後、各項目について欠損が生じていないことも確認すること。
この問題も同様に、欠損値の補完なのでfillnaメソッドを使用します。
今回の問題では中央値を使用します。
データに欠損値が含まれた状態で中央値を求める場合は、numpy.nanmedian
関数を使用します。
中央値で欠損値を補完します。
1 | df_product_3 = df_product.fillna({'unit_price': np.round(np.nanmedian(df_product['unit_price'])), 'unit_cost': np.round(np.nanmedian(df_product['unit_cost']))}) |
1 | product_cd category_major_cd category_medium_cd category_small_cd unit_price unit_cost |
補完が完了したので、各項目について欠損が生じていないことを確認します。
1 | df_product_3.isnull().sum() |
1 | product_cd 0 |
欠損値が存在していないことが確認できたのでOKです。
第83問目: 数値補完(カテゴリごとの中央値)
P-083: 単価(unit_price)と原価(unit_cost)の欠損値について、各商品の小区分(category_small_cd)ごとに算出した中央値で補完した新たなdf_product_4を作成せよ。なお、中央値について1円未満は四捨五入とし、0.5については偶数寄せでかまわない。補完実施後、各項目について欠損が生じていないことも確認すること。
まずは、df_productの構造を確認します。
1 | df_product.head(10) |
1 | product_cd category_major_cd category_medium_cd category_small_cd unit_price unit_cost |
欠損値の有無を確認します。
1 | df_product.isnull().sum() |
1 | product_cd 0 |
unit_priceとunit_costに欠損があることがわかりました。
まずは問題文の通り各商品の小区分(category_cd)ごとにunit_priceとunit_costの中央値を算出した磯思います。
1 | df_tmp = df_product.groupby('category_small_cd').agg({'unit_price':'median', 'unit_cost':'median'}).reset_index() |
1 | category_small_cd unit_price unit_cost |
各商品の小区分ごとにunit_priceとunit_costの中央値を算出することができました。
カラム名ががunit_price, unit_costとなっていますが、これでは各商品の小区分ごとの中央値であることが分か理にくいので、カラム名を変更します。
1 | df_tmp.columns = ['category_small_cd', 'median_price', 'median_cost'] |
1 | category_small_cd median_price median_cost |
それではdf_productとdf_tmpを内部結合していきます。
内部結合はmergeメソッドで可能です。
1 | df_product_4 = pd.merge(df_product, df_tmp, how='inner', on='category_small_cd') |
1 | product_cd category_major_cd category_medium_cd category_small_cd unit_price unit_cost median_price median_cost |
df_product_4の欠損値の有無を確認します。
1 | df_product_4.isnull().sum() |
1 | product_cd 0 |
unit_priceとunit_costに欠損値があることが確認できます。
この欠損値に対して各商品の小区分ごとに算出した中央値で補完をします。
欠損値がある場合のみ中央値を適用したいので、applyメソッドとlambda式を用いて補完していきます。
1 | # unit_price(下記コードではx[0]がunit_price)に欠損値があった場合は、median_price(下記コードではx[1]がmedian_price)を適用し、そうでない場合は。unit_priceそのまま |
1 | product_cd 0 |
まとめ:データサイエンス100本ノック【問79〜83 回答】で欠陥値の扱いを学びました
本記事で紹介した方法を元にデータサイエンティストとしての知見を深めていただければと思います。
なお、データサイエンティストに必要な知識は、TechAcademyのデータサイエンスコースでの学習がおすすめです。