#1. はじめに
データサイエンス協会から出ているデータサイエンス100本ノックの解説をします。
導入についてはこちらの記事を参考に進めてください(※ MacでDockerを扱います)
基本的には解答の解説ですが別解についても記述しています。
#2. 解説編
P-001: レシート明細のデータフレーム(df_receipt)から全項目の先頭10件を表示し、どのようなデータを保有しているか目視で確認せよ。
# head()で先頭行を参照できる。()カッコ内に件数を入力する。空欄の場合は5行。
df_receipt.head(10)
-002: レシート明細のデータフレーム(df_receipt)から売上日(sales_ymd)、顧客ID(customer_id)、商品コード(product_cd)、売上金額(amount)の順に列を指定し、10件表示させよ。
# [[]](二重カッコ)となっているのはDataFrame型にするため
df_receipt[['sales_ymd', 'customer_id', 'product_cd', 'amount']].head(10)
P-003: レシート明細のデータフレーム(df_receipt)から売上日(sales_ymd)、顧客ID(customer_id)、商品コード(product_cd)、売上金額(amount)の順に列を指定し、10件表示させよ。ただし、sales_ymdはsales_dateに項目名を変更しながら抽出すること。
# [[]]二重カッコ内に'sales_ymd', 'customer_id', 'product_cd', 'amount'を入れることでカラムを選択。
# カラム名を変更するにはrename(columns={変更前のカラム名: 変更後のカラム名})
# head(10)で先頭10行を選択
df_receipt[['sales_ymd', 'customer_id', 'product_cd', 'amount']].rename(columns={'sales_ymd': 'sales_date'}).head(10)
P-004: レシート明細のデータフレーム(df_receipt)から売上日(sales_ymd)、顧客ID(customer_id)、商品コード(product_cd)、売上金額(amount)の順に列を指定し、以下の条件を満たすデータを抽出せよ。
・顧客ID(customer_id)が"CS018205000001"
# 二重カッコ内に'sales_ymd', 'customer_id', 'product_cd', 'amount'を入れることでカラムを選択。
# query()メソッドでDataFrameの行を条件で抽出。
df_receipt[['sales_ymd', 'customer_id', 'product_cd', 'amount']].query('customer_id == "CS018205000001"')
# (別解)
df_receipt[df_receipt['customer_id'] == 'CS018205000001']
参考: https://note.nkmk.me/python-pandas-query/
P-005: レシート明細のデータフレーム(df_receipt)から売上日(sales_ymd)、顧客ID(customer_id)、商品コード(product_cd)、売上金額(amount)の順に列を指定し、以下の条件を満たすデータを抽出せよ。
顧客ID(customer_id)が"CS018205000001"
売上金額(amount)が1,000以上
# 前半部分は、P-004を参考。
# queryメソッドは複数条件の場合、"&"で記述する。
df_receipt[['sales_ymd', 'customer_id', 'product_cd', 'amount']].query('customer_id == "CS018205000001" & amount >= 1000')
参考: https://note.nkmk.me/python-pandas-query/
P-006: レシート明細データフレーム「df_receipt」から売上日(sales_ymd)、顧客ID(customer_id)、商品コード(product_cd)、売上数量(quantity)、売上金額(amount)の順に列を指定し、以下の条件を満たすデータを抽出せよ。
顧客ID(customer_id)が"CS018205000001"
売上金額(amount)が1,000以上または売上数量(quantity)が5以上
# 前半部分は、P-004を参考。
# queryメソッドは複数条件の場合、"&"(かつ) "|"(もしくは)で記述
df_receipt[['sales_ymd', 'customer_id', 'product_cd', 'quantity', 'amount']] \
.query('customer_id=="CS018205000001" & (amount>=1000 | quantity>=5)')
参考: https://note.nkmk.me/python-pandas-query/
P-007: レシート明細のデータフレーム(df_receipt)から売上日(sales_ymd)、顧客ID(customer_id)、商品コード(product_cd)、売上金額(amount)の順に列を指定し、以下の条件を満たすデータを抽出せよ。
顧客ID(customer_id)が"CS018205000001"
売上金額(amount)が1,000以上2,000以下
# P-006を参考
# 売上金額(amount)が1,000以上2,000以下は、1000<=amount<=2000と記述する。
df_receipt[['sales_ymd', 'customer_id', 'product_cd', 'amount']] \
.query('customer_id=="CS018205000001" & 1000<=amount<=2000')
参考: https://note.nkmk.me/python-pandas-query/
P-008: レシート明細のデータフレーム(df_receipt)から売上日(sales_ymd)、顧客ID(customer_id)、商品コード(product_cd)、売上金額(amount)の順に列を指定し、以下の条件を満たすデータを抽出せよ。
顧客ID(customer_id)が"CS018205000001"
商品コード(product_cd)が"P071401019"以外
# P-006を参考
# 以外の表記は、"!=" で表記する。
df_receipt[['sales_ymd', 'customer_id', 'product_cd', 'amount']] \
.query('customer_id=="CS018205000001" & product_cd!="P071401019"')
参考(queryメソッド): https://note.nkmk.me/python-pandas-query/
参考(比較演算): https://www.javadrive.jp/python/if/index4.html
P-009: 以下の処理において、出力結果を変えずにORをANDに書き換えよ。
df_store.query('not(prefecture_cd == "13" | floor_area > 900)')
# query()メソッドでDataFrameの行を条件で抽出。
df_store.query('prefecture_cd != "13" & floor_area <= 900')
P-010: 店舗データフレーム(df_store)から、店舗コード(store_cd)が"S14"で始まるものだけ全項目抽出し、10件だけ表示せよ。
# query()メソッドでDataFrameの行を条件で抽出。
# 前方一致はstartswithを用いる。文字列メソッドはengine='python'でないとquery()メソッドで使えない
df_store.query("store_cd.str.startswith('S14')", engine='python').head(10)
# (別解)
df_store[df_store['store_cd'].str.startswith('S14')].head(10)
参考(startswith): https://note.nkmk.me/python-str-compare/
P-011: 顧客データフレーム(df_customer)から顧客ID(customer_id)の末尾が1のものだけ全項目抽出し、10件だけ表示せよ。
# query()メソッドでDataFrameの行を条件で抽出。
# 後方一致はendswithを用いる。文字列メソッドはengine='python'でないとquery()メソッドで使えない
df_customer.query("customer_id.str.endswith('1')", engine='python').head(10)
参考(startswith): https://note.nkmk.me/python-str-compare/
P-012: 店舗データフレーム(df_store)から横浜市の店舗だけ全項目表示せよ。
# query()メソッドでDataFrameの行を条件で抽出。
# str.contains(): 特定の文字列を含む。
# 文字列メソッドはengine='python'でないとquery()メソッドで使えない
df_store.query("address.str.contains('横浜市')", engine='python')
参考(startswith): https://note.nkmk.me/python-str-compare/
P-013: 顧客データフレーム(df_customer)から、ステータスコード(status_cd)の先頭がアルファベットのA〜Fで始まるデータを全項目抽出し、10件だけ表示せよ。
# query()メソッドでDataFrameの行を条件で抽出。
# str.contains(): 特定の文字列を含む。
# ^(先頭から)、[A-F](A-Fまで)、regex=True(正規表現の場合に必要 ※現在は必要ない)
df_customer.query("status_cd.str.contains('^[A-F]', regex=True)", engine='python').head(10)
参考: https://qiita.com/luohao0404/items/7135b2b96f9b0b196bf3
P-014: 顧客データフレーム(df_customer)から、ステータスコード(status_cd)の末尾が数字の1〜9で終わるデータを全項目抽出し、10件だけ表示せよ。
# df_customer.query("status_cd.str.containsはP-013を参考
# [0-9](0-9まで)、$(文字列の末尾)
df_customer.query("status_cd.str.contains('[0-9]$', regex=True)", engine='python').head(10)
参考: https://qiita.com/luohao0404/items/7135b2b96f9b0b196bf3
P-015: 顧客データフレーム(df_customer)から、ステータスコード(status_cd)の先頭がアルファベットのA〜Fで始まり、末尾が数字の1〜9で終わるデータを全項目抽出し、10件だけ表示せよ。
# df_customer.query("status_cd.str.containsはP-013を参考
# ^(先頭から)、[A-F](AからFまで)、 .(任意の1文字)、*(0回以上の繰り返し)、[0-9](0-9まで)、$(文字列の末尾)
df_customer.query("status_cd.str.contains('^[A-F].*[1-9]$', regex=True)", engine='python').head(10)
# (別解)
df_customer.query("(status_cd.str.contains('^[A-F]')) & \
(status_cd.str.contains('[0-9]$'))", engine='python').head(10)
『 .* 』は、”任意の1文字を繰り返す”つまりはどんな文字が何個あっても良い。
参考: https://qiita.com/luohao0404/items/7135b2b96f9b0b196bf3
P-016: 店舗データフレーム(df_store)から、電話番号(tel_no)が3桁-3桁-4桁のデータを全項目表示せよ。
# # df_customer.query("tel_no.str.containsはP-013を参考
# ^(先頭から)、[0-9](0から9)、{3}(3回の繰り返し)
df_store.query("tel_no.str.contains('^[0-9]{3}-[0-9]{3}-[0-9]{4}', regex=True)", engine='python')
参考: https://qiita.com/luohao0404/items/7135b2b96f9b0b196bf3
P-17: 顧客データフレーム(df_customer)を生年月日(birth_day)で高齢順にソートし、先頭10件を全項目表示せよ。
# 要素でソートするsort_values()
# ソートしたい列のラベル(列名)を第一引数(by)に指定する。
# ascending=True: 昇順(高齢順→生誕日が早い(古い))
df_customer.sort_values('birth_day', ascending=True).head(10)
参考: https://note.nkmk.me/python-pandas-sort-values-sort-index/
P-18: 顧客データフレーム(df_customer)を生年月日(birth_day)で若い順にソートし、先頭10件を全項目表示せよ。
# P-017を参考。
# 若い順なのでascending=False
df_customer.sort_values('birth_day', ascending=False).head(10)
参考: https://note.nkmk.me/python-pandas-sort-values-sort-index/
P-19: レシート明細データフレーム(df_receipt)に対し、1件あたりの売上金額(amount)が高い順にランクを付与し、先頭10件を抽出せよ。項目は顧客ID(customer_id)、売上金額(amount)、付与したランクを表示させること。なお、売上金額(amount)が等しい場合は同一順位を付与するものとする。
# 'customer_id', 'amount'のデータフレームと'amount'をランク付けしたデータフレームを横方向に結合。
# rank()メソッドでランクをつける。method='min'で重複値の最小値の値。
df_tmp = pd.concat([df_receipt[['customer_id', 'amount']], df_receipt['amount'] \
.rank(method='min', ascending=False)], axis=1)
# カラム名が重複しているのでカラム名を再定義する。
df_tmp.columns = ['customer_id', 'amount', 'ranking']
# rankingカラムでソートする。
df_tmp.sort_values('ranking').head(10)
method='min'で1位、2位、3位、3位、5位といった最小値に合わせた値(テストやスポーツの順位)
参考: https://note.nkmk.me/python-pandas-rank/
P-020: レシート明細データフレーム(df_receipt)に対し、1件あたりの売上金額(amount)が高い順にランクを付与し、先頭10件を抽出せよ。項目は顧客ID(customer_id)、売上金額(amount)、付与したランクを表示させること。なお、売上金額(amount)が等しい場合でも別順位を付与すること。
# P-019を参考
# method='first'で同一値(重複値)は登場順に順位付けされる。
df_tmp = pd.concat([df_receipt[['customer_id', 'amount']],
df_receipt['amount'].rank(method='first', ascending=False)], axis=1)
df_tmp.columns = ['customer_id', 'amount', 'ranking']
df_tmp.sort_values('ranking', ascending=True).head(10)
参考: https://note.nkmk.me/python-pandas-rank/