python始めたけど、何をしていいのか分からないので、とりあえず問題解くことにしました。
選んだ問題集は「データサイエンス100本ノック(構造化データ加工編)とは何か」。
いろんな人がすでに解答を上げてますが、自分の備忘録として記録。
まず1本目。
KNOCK-001: データフレームの先頭10件を表示 ★
レシート明細のデータフレーム(df_receipt)から全項目の先頭10件を表示し、どのようなデータを保有しているか目視で確認せよ。
解答
#df_receiptはデータフレーム型(pandas.DataFrame)のオブジェクトで、headはそのメソッド。
df_receipt.head(10)
備忘録
1本目から難しい。
どうやら、このdf_receiptというのがデータフレームでどうやらオブジェクトのひとつみたい。そしてオブジェクトは、その中にメソッドという関数みたいなモノを持てるみたい。このheadというのがメソッドで、それにアクセスするために、このピリオドで繋げた形で呼び出すみたい。
DataFrame型の定義
DataFrameはpandas.core.frameモジュール内で定義されている。以下のPATHにある。
pandas/core/frame.py
このファイル内の、DataFrameクラスの定義
DataFrameはNDFrame(N-dimensional frame)という基底クラスを継承しており、二次元のデータを格納するための構造が用意されている。
class DataFrame(NDFrame):
"""
Two-dimensional, size-mutable, potentially heterogeneous tabular data.
...
"""
head()メソッドの実装
def head(self, n=5):
"""
Return the first `n` rows.
This function returns the first `n` rows for the object based on position.
It is useful for quickly testing if your object has the right type of data in it.
Parameters
----------
n : int, default 5
Number of rows to select.
Returns
-------
DataFrame or Series
The first `n` rows of the caller object.
"""
return self.iloc[:n]
head()メソッドの説明
・self: head()メソッドは、DataFrameクラスのインスタンスメソッドとして定義されているため、selfはそのDataFrameオブジェクトを指す。
・n: メソッドの引数で、返す行数を指定してる。デフォルトは5。
self.iloc[:n]: インデックス位置で行を選択するためのilocインデクサーを使用。ilocを使って、DataFrameの最初のn行を選択し、それを返してる。
本問から学んだこと
オブジェクト内のメソッドにアクセスする方法
オブジェクト.メソッド名(引数)
KNOCK-002: 特定の列を抽出する ★
レシート明細のデータフレーム(df_receipt)から売上日(sales_ymd)、顧客ID(customer_id)、商品コード(product_cd)、売上金額(amount)の順に列を指定し、10件表示させよ。
解答
# df_receipt データフレームから 'sales_ymd'(売上日)、'customer_id'(顧客ID)、'product_cd'(製品コード)、'amount'(売上金額)列を抽出
# 抽出したデータフレームの最初の 10 行を表示
df_receipt[['sales_ymd', 'customer_id', 'product_cd', 'amount']].head(10)
備忘録
このダブルブラケットの意味がまた難しい。データフレームを表現するためにはシングルブラケットの中に、リストを入れないといけないみたい。どうやらpandasの仕様みたいなので、もう覚えるしかない。
本問から学んだこと
・二重ブラケット [[]]: 常に DataFrame 型を返す。複数の列や1つの列を DataFrame として取り出したいときに使う。
・シングルブラケット []: 1つの列を Series 型で取り出す際に使う。
KNOCK-003: 指定列の列名を変更する ★
レシート明細のデータフレーム(df_receipt)から売上日(sales_ymd)、顧客ID(customer_id)、商品コード(product_cd)、売上金額(amount)の順に列を指定し、10件表示させよ。ただし、sales_ymdはsales_dateに項目名を変更しながら抽出すること。
解答
# df_receiptデータフレームから指定したカラム('sales_ymd', 'customer_id', 'product_cd', 'amount')を抽出
# 'sales_ymd' カラムの名前を 'sales_date' に変更し、先頭から10行を表示する
df_receipt[['sales_ymd', 'customer_id', 'product_cd', 'amount']].rename(columns={'sales_ymd': 'sales_date'}).head(10)
備忘録
メソッドチェーン
・renameもheadもpandasのDataFrame型のメソッド。メソッドを繋げて用いることをメソッドチェーンと言う。
class DataFrame(NDFrame):
...
def rename(
self,
mapper=None,
*,
index=None,
columns=None,
axis=None,
copy=True,
inplace=False,
level=None,
errors="ignore",
) -> DataFrame | None:
"""
Alter axes labels.
... (ドキュメントと引数の説明が続く)
"""
...
# メソッドの実装が続く
rename()
・rename() メソッドのデフォルトの動作は、「元のデータフレームを変更せず、新しいデータフレームを返すこと」。そのため、元のデータフレーム (df_receipt) のカラム名は変更さない。
変更したい場合は、1) inplace=True を使用するか、2) 変更結果を再代入する。
本問から学んだこと
・メソッドチェーン
メソッドには繋げて使えるものがある。
・rename メソッドの役割
mapper / index / columns: mapperとして辞書を渡すと、インデックスやカラムの名前を変更できる。
inplace: Trueに設定すると、変更が元のデータフレームに適用される。False(デフォルト)に設定すると、新しいデータフレームを返す。
KNOCK-005: 複数条件に合致する行を抽出する① ★
P-005: レシート明細のデータフレーム(df_receipt)から売上日(sales_ymd)、顧客ID(customer_id)、商品コード(product_cd)、売上金額(amount)の順に列を指定し、以下の条件を満たすデータを抽出せよ。
顧客ID(customer_id)が"CS018205000001"
売上金額(amount)が1,000以上
解答
df_tmp.query('customer_id == "CS018205000001" and amount >= 1000')
#別解
df_tmp[(df_tmp['customer_id'] == 'CS018205000001') & (df_tmp['amount'] >= 1000)]
備忘録
KNOCK-004からcustomer_id == "CS018205000001"もdf_tmp['amount'] >= 1000もブールシリーズ。
index df_tmp['customer_id'] == 'CS018205000001 df_tmp['amount'] >= 1000
0 False False
1 False False
2 False False
3 False False
4 False False
... ... ...
104676 False False
104677 False False
104678 False False
104679 False False
104680 False False
このブールシリーズ2つを比較して、両方Trueのときのみ、Trueとし、さらにブールインデックスを作成する。
本問から学んだこと
&演算子の使い方
& 演算子は、2つのブールシリーズの対応する要素を比較し、両方が True の場合に True を、それ以外は False を返す新しいブールシリーズを作る。