この記事はデータサイエンスを勉強しながら、データサイエンス協会が提供する__データサイエンス100本ノック(構造化データ加工編)__を解く過程を自分用にまとめたものです。
チャプター | リンク | チャプター | リンク |
---|---|---|---|
P-001~P-016 | part1 | P-052~P-062 | part6 |
P-017~P-022 | part2 | P-063~P-068 | part7 |
P-023~P-031 | part3 | P-069~P-078 | part8 |
P-032~P-039 | part4 | P-079~P-088 | part9 |
P-040~P-051 | part5 | P-089~P-100 | part10 |
groupby()
agg()
- 最大値
max()
- 最小値
min()
- 平均値
mean()
- 中央値
median()
- 最頻値
mode()
apply()
- 分散
var()
- 標準偏差
std()
P-023 groupby()
, agg()
P-023: レシート明細データフレーム(df_receipt)に対し、店舗コード(store_cd)ごとに売上金額(amount)と売上数量(quantity)を合計せよ。
df_receipt.groupby('store_cd').agg({'amount':'sum', 'quantity':'sum'}).reset_index()
groupby('列名')
:引数に列名を指定するとその列の値ごとにグルーピングされる。
返されるのはGroupByオブジェクトでそれ自体をprint()で出力しても中身は表示されない。
グルーピングしたオブジェクトの処理に関しては以下のページを参照。
P-024 max()
P-024: レシート明細データフレーム(df_receipt)に対し、顧客ID(customer_id)ごとに最も新しい売上日(sales_ymd)を求め、10件表示せよ。
df_receipt.groupby('customer_id').sales_ymd.max().reset_index().head(10)
P-025 min()
P-025: レシート明細データフレーム(df_receipt)に対し、顧客ID(customer_id)ごとに最も古い売上日(sales_ymd)を求め、10件表示せよ。
df_receipt.groupby('customer_id').sales_ymd.min().reset_index().head(10)
P-026
P-026: レシート明細データフレーム(df_receipt)に対し、顧客ID(customer_id)ごとに最も新しい売上日(sales_ymd)と古い売上日を求め、両者が異なるデータを10件表示せよ。
df_max = df_receipt.groupby('customer_id').sales_ymd.max().reset_index()
df_min = df_receipt.groupby('customer_id').sales_ymd.min().reset_index()
df_max_min = pd.concat([df_max, df_min['sales_ymd']], axis=1)
df_max_min.columns = ['customer_id', 'sales_ymd_max', 'sales_ymd_min']
df_max_min.query('sales_ymd_max != sales_ymd_min').head(10)
最も新しい売り上げ日(df_max
)と最も古い売り上げ日(df_min
)のデータフレームを作り、それを横方向に結合したdf_max_min
を作成。
その後、カラム名を変更し、条件に合うものを出力した。
df_tmp = df_receipt.groupby('customer_id').agg({'sales_ymd':['max','min']}).reset_index()
df_tmp.columns = ["_".join(pair) for pair in df_tmp.columns]
#df_tmp.columns = ['customer_id', 'sales_ymd_max', 'sales_ymd_min'] でも可
df_tmp.query('sales_ymd_max != sales_ymd_min').head(10)
解答ではagg()
メソッドを使って上のように書いている。
2行目でリスト内包表記を使いカラム名を変更している。
P-027 mean()
P-027: レシート明細データフレーム(df_receipt)に対し、店舗コード(store_cd)ごとに売上金額(amount)の平均を計算し、降順でTOP5を表示せよ。
df_receipt.groupby('store_cd').amount.mean().reset_index().sort_values('amount', ascending=False).head(5)
agg()
メソッドを使うなら
df_receipt.groupby('store_cd').agg({'amount':'mean'}).reset_index().sort_values('amount', ascending=False).head(5)
P-028 median()
P-028: レシート明細データフレーム(df_receipt)に対し、店舗コード(store_cd)ごとに売上金額(amount)の中央値を計算し、降順でTOP5を表示せよ。
df_receipt.groupby('store_cd').amount.median().reset_index().sort_values('amount', ascending=False).head(5)
これもP-027と同様にamount.median()
をagg({'amount':'median'})
と書いても同様の結果を得られる。
P-029 mode()
, apply()
P-029: レシート明細データフレーム(df_receipt)に対し、店舗コード(store_cd)ごとに商品コード(product_cd)の最頻値を求めよ。
df_receipt.groupby('store_cd').product_cd.apply(lambda x: x.mode()).reset_index()
GroupByオブジェクトの最頻値は他の関数sum
,mean
,median
等と違い、そのまま使うことができない。
apply()やvalue_counts()を組み合わせる必要がある。
apply()
:引数に一次元配列に適用可能な関数を渡す。
デフォルトで各列、axis=1
で各行に適用される。
解答では無名関数( lambda
)を使っている。
P-030 var()
P-030: レシート明細データフレーム(df_receipt)に対し、店舗コード(store_cd)ごとに売上金額(amount)の標本分散を計算し、降順でTOP5を表示せよ。
df_receipt.groupby('store_cd').amount.var(ddof=0).reset_index().sort_values('amount', ascending=False).head(5)
分散の式
$$ s^2 = \frac{1}{n} \sum_{i=1}^{n} (x_i - \bar{x})^2 $$
解答にも書いてあるんですがNumpyとPandasでは分散var()
と標準偏差std()
のデフォルト値が変わってきます。
これはNumpyはデフォルト値で標本分散が求まり、Pandasでは不偏分散の値が求まるようになっているからだそうです。
var()
で分散を計算する際、平均との偏差の2乗の和をn - ddof
で割ります。
Pandasではデフォルトがddof=1
であるため、引数にddof=0
を渡します。
P-031 std()
P-031: レシート明細データフレーム(df_receipt)に対し、店舗コード(store_cd)ごとに売上金額(amount)の標本標準偏差を計算し、降順でTOP5を表示せよ。
df_receipt.groupby('store_cd').amount.std(ddof=0).reset_index().sort_values('amount', ascending=False).head(5)
P-030と同じようにstd()
の引数にddof=0
を渡します。