【Python初心者でも分かる】データサイエンティスト協会の100本ノック|欠損値の処理

スポンサーリンク
Python
【初心者必見】プログラミング言語Pythonでできること5選
プログラミング言語の一つであるPythonはコードが理解しやすく、いろんな用途に使える汎用性があります。ですので、全くの初心者にもおすすめしているサイトが多いです。 ここで改めて、Pythonを勉強したい人やデータ分析、AI開発をして...
初心者に人気のプログラミング言語Pythonは独学可能か?
Pythonは非常に人気のあるプログラミング言語で、まったくの初心者でも独学が可能と言われています。 Pythonはさまざまな目的に使える、汎用性のあるプログラミング言語です。 プログラミングは「独学が難しい」と言われていま...

データサイエンティスト協会の100本ノックがGitHubに公開しているデータとPythonコードを初心者にでも分かるように解説していきます。

今回は79~84本です。内容は主に、データから新たなデータを作成する「欠損値を処理する方法」について解説していきます。

Pythonの環境設定は以下の記事を参考にして下さい。

【2021年最新】M1 mac でanacondaをインストールする方法

【2021年最新】WindowsでAnacondaをインストールする方法

  1. 欠損値を処理する方法
    1. P-079: 商品データフレーム(df_product)の各項目に対し、欠損数を確認せよ。
    2. P-080: 商品データフレーム(df_product)のいずれかの項目に欠損が発生しているレコードを全て削除した新たなdf_product_1を作成せよ。なお、削除前後の件数を表示させ、前設問で確認した件数だけ減少していることも確認すること。
    3. P-081: 単価(unit_price)と原価(unit_cost)の欠損値について、それぞれの平均値で補完した新たなdf_product_2を作成せよ。なお、平均値について1円未満は四捨五入とし、0.5については偶数寄せでかまわない。補完実施後、各項目について欠損が生じていないことも確認すること。
    4. P-082: 単価(unit_price)と原価(unit_cost)の欠損値について、それぞれの中央値で補完した新たなdf_product_3を作成せよ。なお、中央値について1円未満は四捨五入とし、0.5については偶数寄せでかまわない。補完実施後、各項目について欠損が生じていないことも確認すること。
    5. P-083: 単価(unit_price)と原価(unit_cost)の欠損値について、各商品の小区分(category_small_cd)ごとに算出した中央値で補完した新たなdf_product_4を作成せよ。なお、中央値について1円未満は四捨五入とし、0.5については偶数寄せでかまわない。補完実施後、各項目について欠損が生じていないことも確認すること。
    6. P-084: 顧客データフレーム(df_customer)の全顧客に対し、全期間の売上金額に占める2019年売上金額の割合を計算せよ。ただし、販売実績のない場合は0として扱うこと。そして計算した割合が0超のものを抽出せよ。 結果は10件表示させれば良い。また、作成したデータにNAやNANが存在しないことを確認せよ。

欠損値を処理する方法

まずは、以下からダウンロードして下さい。

GitHubからデータをダウンロードする方法

P-079: 商品データフレーム(df_product)の各項目に対し、欠損数を確認せよ。

import pandas as pd
df_product = pd.read_csv("product.csv")

df_product.isnull().sum()

出力:

isnull() で、欠損値であれば Trueを、欠損値でなければ Falseをかえします。その結果を sum() つまり合計することで、欠損値の数を表示してくれます。

データフレームに .isnull().sum() するだけで、欠損値の数が分かるため、データ分析では最初に、必ず行う作業になります。

P-080: 商品データフレーム(df_product)のいずれかの項目に欠損が発生しているレコードを全て削除した新たなdf_product_1を作成せよ。なお、削除前後の件数を表示させ、前設問で確認した件数だけ減少していることも確認すること。

df_product_1 = df_product.dropna()

print(len(df_product))
print(len(df_product_1))

出力:

データフレームに .dropna() するだけで、1つでも欠損値のあるデータ行は削除されます。

もとのデータ数が 10030 であるのに対して、dropna() で欠損値を削除したデータ数は 10023 で、7つでのデータが削除されてたことが確認できます。

実際のデータ分析でも、このような確認作業が必要です。1つの工程で少しでも間違うと、分析結果が大きく間違うことも多くあるためです。

P-081: 単価(unit_price)と原価(unit_cost)の欠損値について、それぞれの平均値で補完した新たなdf_product_2を作成せよ。なお、平均値について1円未満は四捨五入とし、0.5については偶数寄せでかまわない。補完実施後、各項目について欠損が生じていないことも確認すること。

import numpy as np

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"]))})
df_product_2.isnull().sum()

出力:

データフレームに .fillna で、欠損値を補完(代わりの値を入れること)できます。

np.round() 内に数値データを入れると、小数点以下を四捨五入してくれます。

np.nanmean() 内に数値データを入れると、欠損値があっても平均値を算出してくれます。

P-082: 単価(unit_price)と原価(unit_cost)の欠損値について、それぞれの中央値で補完した新たなdf_product_3を作成せよ。なお、中央値について1円未満は四捨五入とし、0.5については偶数寄せでかまわない。補完実施後、各項目について欠損が生じていないことも確認すること。

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"]))})
df_product_3.isnull().sum()

出力:

np.nanmedian() 内に数値データを入れると、欠損値があっても中央値を算出してくれます。

P-083: 単価(unit_price)と原価(unit_cost)の欠損値について、各商品の小区分(category_small_cd)ごとに算出した中央値で補完した新たなdf_product_4を作成せよ。なお、中央値について1円未満は四捨五入とし、0.5については偶数寄せでかまわない。補完実施後、各項目について欠損が生じていないことも確認すること。

df_83 = df_product.groupby("category_small_cd").\
    agg({"unit_price":"median","unit_cost":"median"}).reset_index()
df_83.columns = ["category_small_cd","median_price","median_cost"]

df_product_4 = pd.merge(df_product,df_83,how="inner",on="category_small_cd")

df_product_4["unit_price"] = df_product_4[["unit_price","median_price"]].\
                    apply(lambda x: np.round(x[1]) if np.isnan(x[0]) else x[0],axis=1)

df_product_4["unit_cost"] = df_product_4[["unit_cost","median_cost"]].\
                    apply(lambda x: np.round(x[1]) if np.isnan(x[0]) else x[0],axis=1)
df_product_4.isnull().sum()

出力:

まずは、出力結果をみてみましょう。

すべでのデータの欠損値の数が0になっていることが確認できました。うまく欠損値を補完できたようです。

では、コードを見ていきましょう。

少しややこしく感じるかもしれませんが、今までの問題ができていれば難しくないです。下の4行のコードが分かりにくいかもしれません。

データが欠損値なら、作成した中央値を補完する。

データが欠損値でないのなら、そのままのデータを使う。

ということを行っています。

P-084: 顧客データフレーム(df_customer)の全顧客に対し、全期間の売上金額に占める2019年売上金額の割合を計算せよ。ただし、販売実績のない場合は0として扱うこと。そして計算した割合が0超のものを抽出せよ。 結果は10件表示させれば良い。また、作成したデータにNAやNANが存在しないことを確認せよ。

df_receipt = pd.read_csv("receipt.csv")
df_customer = pd.read_csv("customer.csv")

df_84_2019 = df_receipt.query("20190101 <= sales_ymd <= 20191231")
df_84_2019 = pd.merge(df_customer["customer_id"],
                      df_84_2019[["customer_id","amount"]],
                      how="left",on="customer_id").\
                          groupby("customer_id").sum().reset_index().\
                              rename(columns={"amount":"amount_2019"})

df_84_total = pd.merge(df_customer["customer_id"],
                       df_receipt[["customer_id","amount"]],
                       how="left",on="customer_id").\
                           groupby("customer_id").sum().reset_index()

df_84 = pd.merge(df_84_2019,df_84_total,how="inner",on="customer_id")
df_84["amount_2019"] = df_84["amount_2019"].fillna(0) # 欠損値に0を補完
df_84["amount"] = df_84["amount"].fillna(0) # 欠損値に0を補完

df_84["amount_rate"] = df_84["amount_2019"]/df_84["amount"]
df_84["amount_rate"] = df_84["amount_rate"].fillna(0)
df_84.query("amount_rate>0").head(10)

出力:

10行を表示させています。欠損値を表す NA や NAN がないことが確認できます。

では、コードをもう少し詳しくみてみましょう。

fillna(0) で、欠損値に0を補完しています。

どのような数値を補完するかは、分析の目的やデータの性質によるため、まずは補完方法だけ覚えておきましょう。まあ覚えなくてもコードを保存して、必要に応じてコピペすればいいのですが。。。

欠損値の種類と対処方法
データ分析をするうえで、データに欠損があることはよくあります。原因は様々ですが、例として、アンケート用紙の未回答、データの入力忘れ、機器の不具合などが挙げられます。 このようなデータの欠損は分析結果に影響を与える可能性...

データサイエンティスト協会の100本ノックを解説|ダウンロードから読み込みまで

データサイエンティスト協会の100本ノックを解説|データの抽出

データサイエンティスト協会の100本ノックを解説|変数の一部を使ってデータを抽出する

データサイエンティスト協会の100本ノックを解説|ソート(順序で整列)

データサイエンティスト協会の100本ノックを解説|グループ分け

データサイエンティスト協会の100本ノック|新たなデータフレームの作成

データサイエンティスト協会の100本ノック|日付データ

データサイエンティスト協会の100本ノック|特徴量エンジニアリング

データサイエンティスト協会の100本ノック|変数を整える

データサイエンティスト協会の100本ノック|小数点の処理

データサイエンティスト協会の100本ノック|時系列データの処理

コメント

タイトルとURLをコピーしました