1. はじめに
前回に引き続き、データサイエンス100本ノックの解説を行う。
[データサイエンス100本ノック解説(P001~020)] (https://qiita.com/ProgramWataru/items/42ff579a3cdb4f0ad158)
データサイエンス100本ノック解説(P021~040)
データサイエンス100本ノック解説(P041~060)
導入についてはこちらの記事を参考に進めてください(※ MacでDockerを扱います)
基本的には解答の解説ですが別解についても記述しています。
※徐々に難易度が上がってきています。
#2. 解説編
P-061: レシート明細データフレーム(df_receipt)の売上金額(amount)を顧客ID(customer_id)ごとに合計し、合計した売上金額を常用対数化(底=10)して顧客ID、売上金額合計とともに表示せよ。ただし、顧客IDが"Z"から始まるのものは非会員を表すため、除外して計算すること。結果は10件表示させれば良い。
# 顧客IDが"Z"から始まるのものを除く
# レシート明細データフレーム(df_receipt)の売上金額(amount)を顧客ID(customer_id)ごとに合計
df_sales_amount = df_receipt.query('not customer_id.str.startswith("Z")',
engine='python').groupby('customer_id').amount.sum().reset_index()
# 売上金額(amount)を常用対数化(底=10)する。
# applyで適用するmath.log10(x+1)た常用対数化+1は必要。
df_sales_amount['amount_log10'] = df_amount_sum['amount'].apply(lambda x: math.log10(x+1))
df_sales_amount.head(10)
# (別解) np.log10を用いている
df_sales_amount = df_receipt.query('not customer_id.str.startswith("Z")', engine='python'). \
groupby('customer_id').agg({'amount':'sum'}).reset_index()
df_sales_amount['amount_log10'] = np.log10(df_sales_amount['amount'] + 1)
df_sales_amount.head(10)
参考: Pythonで指数関数・対数関数を計算(exp, log, log10, log2)
P-062: レシート明細データフレーム(df_receipt)の売上金額(amount)を顧客ID(customer_id)ごとに合計し、合計した売上金額を自然対数化(底=e)して顧客ID、売上金額合計とともに表示せよ。ただし、顧客IDが"Z"から始まるのものは非会員を表すため、除外して計算すること。結果は10件表示させれば良い。
# 顧客IDが"Z"から始まるのものを除く
# レシート明細データフレーム(df_receipt)の売上金額(amount)を顧客ID(customer_id)ごとに合計
df_sales_amount = df_receipt.query('not customer_id.str.startswith("Z")', engine='python') \
.groupby('customer_id').amount.sum().reset_index()
# 売上金額(amount)を自然対数化(底=e)する(+1を忘れない)
df_sales_amount['amount_log'] = np.log(df_sales_amount['amount'] + 1)
df_sales_amount.head()
# (別解)
df_sales_amount = df_receipt.query('not customer_id.str.startswith("Z")', engine='python'). \
groupby('customer_id').agg({'amount':'sum'}).reset_index()
df_sales_amount['amount_loge'] = np.log(df_sales_amount['amount'] + 1)
df_sales_amount.head(10)
参考: Pythonで指数関数・対数関数を計算(exp, log, log10, log2)
P-063: 商品データフレーム(df_product)の単価(unit_price)と原価(unit_cost)から、各商品の利益額を算出せよ。結果は10件表示させれば良い。
# 商品データフレーム(df_product)をコピーする。
df_tmp = df_product.copy()
# 単価(unit_price)から原価(unit_cost)を引いた利益額(unit_profit)を表示する
df_tmp['unit_profit'] = df_tmp['unit_price'] - df_tmp['unit_cost']
df_tmp.head(10)
P-064: 商品データフレーム(df_product)の単価(unit_price)と原価(unit_cost)から、各商品の利益率の全体平均を算出せよ。 ただし、単価と原価にはNULLが存在することに注意せよ。
# 商品データフレーム(df_product)をコピーする。
df_tmp = df_product.copy()
# 単価(unit_price)から原価(unit_cost)を引いた値を単価(unit_price)で割った、利益率(unit_profit_rate)を表示する
df_tmp['unit_profit_rate'] = (df_tmp['unit_price'] - df_tmp['unit_cost']) / df_tmp['unit_price']
# 利益額の平均を算出する(Nullを除く: skipna=True)
df_tmp['unit_profit_rate'].mean(skipna=True)
参考: pandasで、行 or 列内に欠損値がある時に、無視して加算・無視せず加算する方法
P-065: 商品データフレーム(df_product)の各商品について、利益率が30%となる新たな単価を求めよ。ただし、1円未満は切り捨てること。そして結果を10件表示させ、利益率がおよそ30%付近であることを確認せよ。ただし、単価(unit_price)と原価(unit_cost)にはNULLが存在することに注意せよ。
# 商品データフレーム(df_product)をコピーする。
df_tmp = df_product.copy()
# 原価(unit_cost)から利益率が30%となる新たな単価(new_price)を求める(1円未満は切り捨て)
# 原価(unit_cost) x 10/7 (利益率が30%となる)計算式。math.floorはエラー
df_tmp['new_price'] = np.floor(df_tmp['unit_cost'] * 10/7)
# 利益率を確認する
df_tmp['new_price_rate'] = (df_tmp['new_price'] - df_tmp['unit_cost']) / df_tmp['new_price']
# 利益額の平均を算出する(Nullを除く)
df_tmp.head(10)
# (別解)
df_tmp = df_product.copy()
df_tmp['new_price'] = df_tmp['unit_cost'].apply(lambda x: np.floor(x / 0.7))
df_tmp['new_profit_rate'] = (df_tmp['new_price'] - df_tmp['unit_cost']) / df_tmp['new_price']
df_tmp.head(10)
参考: 【NumPy】実数→整数(四捨五入・切り捨て・切り上げ)
P-066: 商品データフレーム(df_product)の各商品について、利益率が30%となる新たな単価を求めよ。今回は、1円未満を四捨五入すること(0.5については偶数方向の丸めで良い)。そして結果を10件表示させ、利益率がおよそ30%付近であることを確認せよ。ただし、単価(unit_price)と原価(unit_cost)にはNULLが存在することに注意せよ。
# 商品データフレーム(df_product)をコピーする。
df_tmp = df_product.copy()
# 原価(unit_cost)から利益率が30%となる新たな単価(new_price)を求める(1円未満を四捨五入0.5については偶数方向の丸め)
# 原価(unit_cost) x 10/7 (利益率が30%となる)計算式。
df_tmp['new_price'] = np.round(df_tmp['unit_cost'] * 10/7)
# 利益率を確認する
df_tmp['new_price_rate'] = (df_tmp['new_price'] - df_tmp['unit_cost']) / df_tmp['new_price']
# 利益額の平均を算出する(Nullを除く)
df_tmp.head(10)
# (別解)
# 組み込みのroundはNaNでエラーとなるが、numpy.roundはエラーとならない
df_tmp = df_product.copy()
df_tmp['new_price'] = df_tmp['unit_cost'].apply(lambda x: np.round(x / 0.7))
df_tmp['new_profit_rate'] = (df_tmp['new_price'] - df_tmp['unit_cost']) / df_tmp['new_price']
df_tmp.head(10)
参考: pandasで数値を丸める(四捨五入、偶数への丸め)
P-067: 商品データフレーム(df_product)の各商品について、利益率が30%となる新たな単価を求めよ。今回は、1円未満を切り上げること。そして結果を10件表示させ、利益率がおよそ30%付近であることを確認せよ。ただし、単価(unit_price)と原価(unit_cost)にはNULLが存在することに注意せよ。
# 商品データフレーム(df_product)をコピーする。
df_tmp = df_product.copy()
# 原価(unit_cost)から利益率が30%となる新たな単価(new_price)を求める(1円未満を切り上げ)
# 原価(unit_cost) x 10/7 (利益率が30%となる)計算式。
df_tmp['new_price'] = np.ceil(df_tmp['unit_cost'] * 10/7)
# 利益率を確認する
df_tmp['new_price_rate'] = (df_tmp['new_price'] - df_tmp['unit_cost']) / df_tmp['new_price']
# 利益額の平均を算出する(Nullを除く)
df_tmp.head(10)
# (別解)
# コード例1
# math.ceilはNaNでエラーとなるが、numpy.ceilはエラーとならない
df_tmp = df_product.copy()
df_tmp['new_price'] = df_tmp['unit_cost'].apply(lambda x: np.ceil(x / 0.7))
df_tmp['new_profit_rate'] = (df_tmp['new_price'] - df_tmp['unit_cost']) / df_tmp['new_price']
df_tmp.head(10)
参考: 【NumPy】実数→整数(四捨五入・切り捨て・切り上げ)
P-068: 商品データフレーム(df_product)の各商品について、消費税率10%の税込み金額を求めよ。 1円未満の端数は切り捨てとし、結果は10件表示すれば良い。ただし、単価(unit_price)にはNULLが存在することに注意せよ。
# 商品データフレーム(df_product)をコピーする。
df_tmp = df_product.copy()
# 消費税率10%の税込み金額(price_tax)を求める。(単価(unit_price)*1.1)
df_tmp['price_tax'] = np.floor(df_tmp['unit_price'] * 1.1)
df_tmp.head(10)
# (別解)
# math.floorはNaNでエラーとなるが、numpy.floorはエラーとならない
df_tmp = df_product.copy()
df_tmp['price_tax'] = df_tmp['unit_price'].apply(lambda x: np.floor(x * 1.1))
df_tmp.head(10)
参考: pandasで数値を丸める(四捨五入、偶数への丸め)
P-069: レシート明細データフレーム(df_receipt)と商品データフレーム(df_product)を結合し、顧客毎に全商品の売上金額合計と、カテゴリ大区分(category_major_cd)が"07"(瓶詰缶詰)の売上金額合計を計算の上、両者の比率を求めよ。抽出対象はカテゴリ大区分"07"(瓶詰缶詰)の購入実績がある顧客のみとし、結果は10件表示させればよい。
# レシート明細データフレーム(df_receipt)と商品データフレーム(df_product)を結合(pd.merge, キーはproduct_cd)
# 顧客毎に全商品の売上金額合計を算出する
df_tmp_1 = pd.merge(df_receipt, df_product, on='product_cd',
how='inner').groupby('customer_id').amount.sum().reset_index()
# カテゴリ大区分(category_major_cd)が"07"(瓶詰缶詰)の売上金額合計
# merge(df1, df2, on='キー', how='inner')で結合
# groupbyで顧客ごとにグルーピング。amount.sum()で売上金額合計
df_tmp_2 = pd.merge(df_receipt, df_product.query('category_major_cd=="07"'), on='product_cd',
how='inner').groupby('customer_id').amount.sum().reset_index()
# df_tmp1とdf_tmp2を結合する。
df_tmp_3 = pd.merge(df_tmp_1, df_tmp_2, on='customer_id', how='inner')
# 両者の比率を求める。
df_tmp_3['rate_07'] = df_tmp_3['amount_y'] / df_tmp_3['amount_x']
df_tmp_3.head(10)
# (別解) agg({カラム: 適用する関数})
df_tmp_1 = pd.merge(df_receipt, df_product,
how='inner', on='product_cd').groupby('customer_id').agg({'amount':'sum'}).reset_index()
df_tmp_2 = pd.merge(df_receipt, df_product.query('category_major_cd == "07"'),
how='inner', on='product_cd').groupby('customer_id').agg({'amount':'sum'}).reset_index()
df_tmp_3 = pd.merge(df_tmp_1, df_tmp_2, how='inner', on='customer_id')
df_tmp_3['rate_07'] = df_tmp_3['amount_y'] / df_tmp_3['amount_x']
df_tmp_3.head(10)
参考: pandas.DataFrameを結合するmerge, join(列・インデックス基準)
P-070: レシート明細データフレーム(df_receipt)の売上日(sales_ymd)に対し、顧客データフレーム(df_customer)の会員申込日(application_date)からの経過日数を計算し、顧客ID(customer_id)、売上日、会員申込日とともに表示せよ。結果は10件表示させれば良い(なお、sales_ymdは数値、application_dateは文字列でデータを保持している点に注意)。
# レシート明細データフレーム(df_receipt)と顧客データフレーム(df_customer)を結合する
df_tmp = pd.merge(df_receipt[['sales_ymd', 'customer_id']],
df_customer[['application_date', 'customer_id']], how='inner', on='customer_id')
# 重複部分を削除する
df_tmp = df_tmp.drop_duplicates()
# 会員申込日(application_date)からの売上日(sales_ymd)を引く
# pandas.to_datetime()関数を使うと、日時(日付・時間)を表した文字列の列pandas.Seriesをdatetime64[ns]型に変換できる。
# sales_ymdは数値型のためastype('str')で文字列型へ変更
df_tmp['elapsed_date'] = pd.to_datetime(df_tmp['sales_ymd'].astype('str')) - pd.to_datetime(df_tmp['application_date'])
df_tmp[['sales_ymd', 'application_date', 'elapsed_date']].head(10)
参考: pandas.DataFrame, Seriesの重複した行を抽出・削除
参考: pandasで日付・時間の列を処理(文字列変換、年月日抽出など)
P-071: レシート明細データフレーム(df_receipt)の売上日(sales_ymd)に対し、顧客データフレーム(df_customer)の会員申込日(application_date)からの経過月数を計算し、顧客ID(customer_id)、売上日、会員申込日とともに表示せよ。結果は10件表示させれば良い(なお、sales_ymdは数値、application_dateは文字列でデータを保持している点に注意)。1ヶ月未満は切り捨てること。
# pd.mergeでレシート明細データフレーム(df_receipt)と顧客データフレーム(df_customer)を結合(キーはcustomer_id)
df_tmp = pd.merge(df_receipt[['customer_id', 'sales_ymd']],
df_customer[['customer_id', 'application_date']], how='inner', on='customer_id')
# 重複を削除する(drop_duplicates())
df_tmp = df_tmp.drop_duplicates()
# pandas.to_datetime()関数を使うと、日時(日付・時間)を表した文字列の列pandas.Seriesをdatetime64[ns]型に変換できる。
df_tmp['sales_ymd'] = pd.to_datetime(df_tmp['sales_ymd'].astype('str'))
df_tmp['application_date'] = pd.to_datetime(df_tmp['application_date'])
# 月数を計算するrelativedelta(datetime1, datetime2) datetime1 - datetime2
df_tmp['elapsed_date'] = df_tmp[['sales_ymd', 'application_date']].apply(lambda x:
relativedelta(x[0], x[1]).years * 12 + relativedelta(x[0], x[1]).months, axis=1)
# 顧客ID(customer_id)でソートし、10件表示する
df_tmp.sort_values('customer_id').head(10)
P-072: レシート明細データフレーム(df_receipt)の売上日(sales_ymd)に対し、顧客データフレーム(df_customer)の会員申込日(application_date)からの経過年数を計算し、顧客ID(customer_id)、売上日、会員申込日とともに表示せよ。結果は10件表示させれば良い。(なお、sales_ymdは数値、application_dateは文字列でデータを保持している点に注意)。1年未満は切り捨てること。
# pd.mergeでレシート明細データフレーム(df_receipt)と顧客データフレーム(df_customer)を結合(キーはcustomer_id)
df_tmp = pd.merge(df_receipt[['customer_id', 'sales_ymd']],
df_customer[['customer_id', 'application_date']], how='inner', on='customer_id')
# 重複を削除する(drop_duplicates())
df_tmp = df_tmp.drop_duplicates()
# pandas.to_datetime()関数を使うと、日時(日付・時間)を表した文字列の列pandas.Seriesをdatetime64[ns]型に変換できる。
df_tmp['sales_ymd'] = pd.to_datetime(df_tmp['sales_ymd'].astype('str'))
df_tmp['application_date'] = pd.to_datetime(df_tmp['application_date'])
# 経過年数を計算する。relativedelta(datetime1, datetime2).yearsで年数差(axis=1で行に沿った処理)
df_tmp['elapsed_date'] = df_tmp[['sales_ymd', 'application_date']].apply(lambda x:
relativedelta(x[0], x[1]).years, axis=1)
df_tmp.sort_values('customer_id').head(10)
P-073: レシート明細データフレーム(df_receipt)の売上日(sales_ymd)に対し、顧客データフレーム(df_customer)の会員申込日(application_date)からのエポック秒による経過時間を計算し、顧客ID(customer_id)、売上日、会員申込日とともに表示せよ。結果は10件表示させれば良い(なお、sales_ymdは数値、application_dateは文字列でデータを保持している点に注意)。なお、時間情報は保有していないため各日付は0時0分0秒を表すものとする。
# pd.mergeでレシート明細データフレーム(df_receipt)と顧客データフレーム(df_customer)を結合(キーはcustomer_id)
df_tmp = pd.merge(df_receipt[['customer_id', 'sales_ymd']],
df_customer[['customer_id', 'application_date']], how='inner', on='customer_id')
# 重複を削除する(drop_duplicates())
df_tmp = df_tmp.drop_duplicates()
# pandas.to_datetime()関数を使うと、日時(日付・時間)を表した文字列の列pandas.Seriesをdatetime64[ns]型に変換できる。
df_tmp['sales_ymd'] = pd.to_datetime(df_tmp['sales_ymd'].astype('str'))
df_tmp['application_date'] = pd.to_datetime(df_tmp['application_date'])
# エポック秒による経過時間を計算(timestamp()メソッドでdatetimeオブジェクトをUNIX時間に変換)
# 注:タイムスタンプは、ナノ秒を含むunix時間(10 ** 9で除算)
df_tmp['elapsed_date'] = (df_tmp['sales_ymd'].astype(np.int64) / 10**9) - \
(df_tmp['application_date'].astype(np.int64) / 10 **9)
# 10件表示する
df_tmp.head(10)
# なぜ10の9乗で除算するのか?
nano_time = pd.to_datetime('1970-01-02')
nano_time.value
# >>>86400000000000
エポック時間は1970-01-01からの経過時間なので24時間x60分x60秒=86400秒
unix時間がナノ秒(10の9乗)であることがわかる
P-074: レシート明細データフレーム(df_receipt)の売上日(sales_ymd)に対し、当該週の月曜日からの経過日数を計算し、売上日、当該週の月曜日付とともに表示せよ。結果は10件表示させれば良い(なお、sales_ymdは数値でデータを保持している点に注意)。
# レシート明細データフレーム(df_receipt)の顧客データ(customer_id),売上日(sales_ymd)
df_tmp = df_receipt[['customer_id', 'sales_ymd']]
# 重複を削除する
df_tmp = df_tmp.drop_duplicates()
# datetime64[ns]型に変換
df_tmp['sales_ymd'] = pd.to_datetime(df_tmp['sales_ymd'].astype('str'))
# 月曜のデータを追加する。(relativedelta(days=x.weekday())月曜:0, 火曜:1・・・)
df_tmp['monday'] = df_tmp['sales_ymd'].apply(lambda x: x - relativedelta(days=x.weekday()))
# 売上日(sales_ymd)から月曜日を引いて経過日数を求める
df_tmp['elapsed_weekday'] = df_tmp['sales_ymd'] - df_tmp['monday']
df_tmp.head(10)
参考: pandasのdatetime型の取り扱い(pd.to_datetime、pd.offsets、タイムゾーン)
P-075: 顧客データフレーム(df_customer)からランダムに1%のデータを抽出し、先頭から10件データを抽出せよ。
# 顧客データフレーム(df_customer)より抽出する(sample)
# ランダムに1%のデータは引数frac=0.01
df_customer.sample(frac=0.01).head(10)
参考: pandasの行・列をランダムサンプリング(抽出)するsample
P-076: 顧客データフレーム(df_customer)から性別(gender_cd)の割合に基づきランダムに10%のデータを層化抽出データし、性別ごとに件数を集計せよ。
# sklearn.model_selection.train_test_splitを使用した例
# _(訓練データ90%)、df_tmp(テストデータ10%)とすることでランダムに10%を抽出する(層化抽出: 引数stratify)
_, df_tmp = train_test_split(df_customer, test_size=0.1, stratify=df_customer['gender_cd'])
# 性別(gender_cd)でグループ分けし、customer_idの件数(count)を集計
df_tmp.groupby('gender_cd').agg({'customer_id' : 'count'})
# (別解)
# sampleメソッドを用いてランダムに抽出(frac=0.1で10%データを抽出)
# 性別(gender_cd)でグループ分けし、customer_idの件数(count)を集計
df_customer.sample(frac=0.1).groupby('gender_cd').agg({'customer_id' : 'count'})
参考: pandasの行・列をランダムサンプリング(抽出)するsample
P-077: レシート明細データフレーム(df_receipt)の売上金額(amount)を顧客単位に合計し、合計した売上金額の外れ値を抽出せよ。ただし、顧客IDが"Z"から始まるのものは非会員を表すため、除外して計算すること。なお、ここでは外れ値を平均から3σ以上離れたものとする。結果は10件表示させれば良い。
# 顧客IDが"Z"から始まるものを除外する
# レシート明細データフレーム(df_receipt)の売上金額(amount)を顧客単位に合計する
df_sales_amount = df_receipt.query("not customer_id.str.startswith('Z')",
engine='python').groupby('customer_id').amount.sum().reset_index()
# 正規化・標準化(平均0、標準偏差1):preprocessing.scale()関数を使う。
df_sales_amount['amount_ss'] = preprocessing.scale(df_sales_amount['amount'])
# 外れ値を抽出する(平均(mean)の ± 3σ(std)以上離れたものを抽出する)
# queryメソッドで条件に合うものを抽出。3σ以上離れたは、絶対値(abs)を用いる
df_sales_amount.query('abs(amount_ss)>=3').head(10)
# (別解)
# 顧客IDが"Z"から始まるものを除外する
# レシート明細データフレーム(df_receipt)の売上金額(amount)を顧客単位に合計する
df_sales_amount = df_receipt.query("not customer_id.str.startswith('Z')",
engine='python').groupby('customer_id').amount.sum().reset_index()
# 各顧客の売り上げ合計の平均、標準偏差を求める
mean = df_sales_amount.describe().loc['mean']
std = df_sales_amount.describe().loc['std']
# 外れ値を抽出する(平均(mean)の ± 3σ(std)以上離れたものを抽出する)
df_sales_amount[(df_sales_amount['amount'] >= int(mean) + 3*int(std)) | \
(df_sales_amount['amount'] <= int(mean) - 3*int(std))].head(10)
参考: Pythonで正規化・標準化(リスト、NumPy配列、pandas.DataFrame)
P-078: レシート明細データフレーム(df_receipt)の売上金額(amount)を顧客単位に合計し、合計した売上金額の外れ値を抽出せよ。ただし、顧客IDが"Z"から始まるのものは非会員を表すため、除外して計算すること。なお、ここでは外れ値を第一四分位と第三四分位の差であるIQRを用いて、「第一四分位数-1.5×IQR」よりも下回るもの、または「第三四分位数+1.5×IQR」を超えるものとする。結果は10件表示させれば良い。
# 顧客IDが"Z"から始まるものを除外する
# レシート明細データフレーム(df_receipt)の売上金額(amount)を顧客単位に合計する
df_sales_amount = df_receipt.query("not customer_id.str.startswith('Z')",
engine='python').groupby('customer_id').amount.sum().reset_index()
# 第一四分位と第三四分位の差であるIQRを求める
pct75 = df_sales_amount['amount'].quantile(0.75)
pct25 = df_sales_amount['amount'].quantile(0.25)
iqr = pct75 - pct25
# 第一四分位数-1.5×IQR(amount_low), 第三四分位数+1.5×IQR(amount_hight)をそれぞれ求める
amount_low = pct25 - (iqr * 1.5)
amount_hight = pct75 + (iqr * 1.5)
# 外れ値を抽出する(@で変数名)
df_sales_amount.query('amount > @amount_hight | amount < @amount_low').head(10)
# (別解) np.percentileを用いた回答
df_sales_amount = df_receipt.query('not customer_id.str.startswith("Z")', engine='python'). \
groupby('customer_id').agg({'amount':'sum'}).reset_index()
pct75 = np.percentile(df_sales_amount['amount'], q=75)
pct25 = np.percentile(df_sales_amount['amount'], q=25)
iqr = pct75 - pct25
amount_low = pct25 - (iqr * 1.5)
amount_hight = pct75 + (iqr * 1.5)
df_sales_amount.query('amount < @amount_low or @amount_hight < amount').head(10)
参考: pandasで分位数・パーセンタイルを取得するquantile
P-079: 商品データフレーム(df_product)の各項目に対し、欠損数を確認せよ。
# isnull()で要素ごとに欠損値か判定
df_product.isnull().sum()
参考: pandasで欠損値NaNが含まれているか判定、個数をカウント
P-080: 商品データフレーム(df_product)のいずれかの項目に欠損が発生しているレコードを全て削除した新たなdf_product_1を作成せよ。なお、削除前後の件数を表示させ、前設問で確認した件数だけ減少していることも確認すること。
# 商品データフレーム(df_product)をコピーする
df_product_1 = df_product.copy()
# 欠損値削除前の件数を確認する
print('削除前: ', len(df_product_1))
# 欠損値を除外(削除)するにはdropna()メソッド
df_product_1.dropna(inplace=True)
print('削除後: ', len(df_product_1))
参考: pandasで欠損値NaNを除外(削除)・置換(穴埋め)・抽出
3. 参考文献
データサイエンス100本ノック
Macでデータサイエンス100本ノックを動かす方法
4. 所感
難易度が問題によってばらつく。難しいものは難しい。