テーブルデータ操作ライブラリ pandas(入門編)

pandas-first-step python
pandas-first-step



よくあるデータの形式として,

  • テーブルデータ
  • 時系列データ
  • テキストデータ
  • 画像データ
  • 音声データ
  • 映像データ

などがありますが,世の中で最も良くあるのは,特に汎用性の高いエクセルのシートで表されるような行列のデータであるテーブルデータと思われます.
このテーブルデータを効率的に操作することができるのが pandas です.
今回は pandas について,ある程度使えるようになるために一部紹介していきます.

今回のコードは,次の github にも載せています.

PythonCourse/010_pandas_firststep at main · KazutoMakino/PythonCourse
Python Course. Contribute to KazutoMakino/PythonCourse development by creating an account on GitHub.

pandas 概要

pandas(パンダズ)は,テーブルデータを効率的に操作することができ,テキストファイルはもちろんのこと,CSV や JSON, excel ファイルの読み書きについても,簡単なコードで実現できます.
また,jupyter への出力も視覚的にキレイに出力させるのもサポートされており,データ分析には欠かせないライブラリと言えます.
ライブラリのインポートは,公式ドキュメント(https://pandas.pydata.org/)にて pd と省略形でインポートしており,この方法が一般的です.

import pandas as pd

pandas は基本的には,pandas.Series と pandas.DataFrame という 2 つのオブジェクトで操作します.
Series は,行の名称が辞書型のキーのように紐付いていて,テーブルの一つの列として扱うことができます.
DataFrame は,行名と列名がある表形式のデータテーブルを扱うことができます.

Series / DataFrame の生成

Series の生成について,構文とその例は以下です.
Series をなにかの変数として代替させる場合,”ser” が良く用いられます.

pd.Series(data=None, index=None, dtype=None, name=None, copy=False)
- data: 要素として入れられるデータで,リストなどのイテラブルオブジェクトが使用可能
- index: 行の名称で,リストなどのイテラブルオブジェクトが使用可能
- dtype: データタイプで,文字列やタイプが使用可能
- name: Series の名称
- copy: True のときに Series を変更した場合に,元のデータが numpy の 1 次元配列である場合は元のデータも変更される
arr = list(range(10, 13))
ser = pd.Series(data=arr)
ser
# 0    10
# 1    11
# 2    12
# dtype: int64

pd.Series(data=arr, index=["a", "b", "c"], dtype=float, name="age")
# a    10.0
# b    11.0
# c    12.0
# Name: age, dtype: float64

pd.Series(data={"a": 10, "b": 11, "c": 12}, name="age")
# a    10
# b    11
# c    12
# Name: age, dtype: int64

続いて,DataFrame の生成について,構文とその例は以下です.
DataFrame をなにかの変数として代替させる場合,”df” が良く用いられます.

pd.DataFrame(data=None, index=None, columns=None, dtype=None, copy=None)
- data: 多次元配列やイテラブルオブジェクトや辞書や DataFrame
- index: 行の名称で,リストなどのイテラブルオブジェクトが使用可能
- columns: 列の名称で,リストなどのイテラブルオブジェクトが使用可能
- dtype: データタイプで,文字列やタイプが使用可能
- copy: True のときに Series を変更した場合に,元のデータが numpy 配列である場合は元のデータも変更される
df = pd.DataFrame(data=arr)
df
#    0
# 0	10
# 1	11
# 2	12

arr2 = [
    [10, 21],
    [11, 22],
    [12, 23],
]
pd.DataFrame(data=arr2, index=["a", "b", "c"], columns=["A", "B"], dtype=float)
#      A	   B
# a	10.0	21.0
# b	11.0	22.0
# c	12.0	23.0

pd.DataFrame(data={"A": [10, 11, 12], "B": [21, 22, 23]}, index=["a", "b", "c"])
#    A	 B
# a	10	21
# b	11	22
# c	12	23

Series / DataFrame の属性

良く使われるものの内一覧としては以下で,Series と DataFrame で共通するものやしないものがあります.

属性SeriesDataFrame
Tなし転置を返す
at指定するインデックスの要素一つにアクセス指定するインデックスとカラムの要素一つにアクセス
columnsなしカラムを返す
hasnansどれかの要素が NaN である場合に True を返すなし
iat指定する行番号の要素一つにアクセス指定する行・列番号の要素一つにアクセス
iloc指定する行番号の要素にアクセス指定する行・列番号の要素にアクセス
indexindex 列を返す<-
loc指定する要素にアクセス<-
nameSeries の名称を返すなし
shape形状を返す<-
size要素数を返す<-
values要素のみを numpy.ndarray で返す<-
properties

上記の属性について,下記で定義する “ser”, “df” を用いて,以下に例を示していきます.

ser = pd.Series(data={"a": 10, "b": 11, "c": 12}, name="series_abc")
ser
# a    10
# b    11
# c    12
# Name: series_abc, dtype: int64

df = pd.DataFrame(data={"A": [10, 11, 12], "B": [20, 21, 22], "C": ["a", "b", "c"]})
df
#    A	 B	C
# 0	10	20	a
# 1	11	21	b
# 2	12	22	c
.T : 転置
df.T
#    0	 1	 2
# A	10	11	12
# B	20	21	22
# C  a	 b	 c
.at : 指定するインデックスやカラムの要素一つにアクセス
ser.at["b"]
# 11

df.at[1,"C"]
# 'b'
.columns : カラムを返す
df.columns
# Index(['A', 'B', 'C'], dtype='object')
.hasnans : どれかの要素が NaN である場合に True を返す
ser.hasnans
# False
.iat : 指定する行番号や列番号の要素一つにアクセス
ser.iat[1]
# 11

df.iat[1, 2]
# 'b'
.iloc : 指定する行番号や列番号の要素にアクセス
ser.iloc[1:]
# b    11
# c    12
# Name: series_abc, dtype: int64

df.iloc[1:, 1:]
#    B	C
# 1	21	b
# 2	22	c
.index : index を返す
ser.index
# Index(['a', 'b', 'c'], dtype='object')

df.index
# RangeIndex(start=0, stop=3, step=1)
.loc : 指定する要素にアクセス
ser.loc[["b","c"]]
# b    11
# c    12
# Name: series_abc, dtype: int64

df.loc[[1, 2], ["B", "C"]]
#    B	C
# 1	21	b
# 2	22	c
.name : Series の名称を返す
ser.name
# 'series_abc'
.shape : 形状を返す
ser.shape
# (3,)

df.shape
# (3, 3)
.size : 要素数を返す
ser.size
# 3

df.size
# 9
.values : 要素のみを numpy.ndarray で返す
ser.values
# array([10, 11, 12], dtype=int64)

df.values
# array([[10, 20, 'a'],
#        [11, 21, 'b'],
#        [12, 22, 'c']], dtype=object)

Series / DataFrame のメソッド

良く使われるものの内一覧としては以下で,Series と DataFrame で共通するものやしないものがあります.
このとおり,メソッドだけでも多くのテーブルデータの操作が可能です.

メソッドSeriesDataFrame
.abs()各要素の絶対値を返す<-
.all(axis=0, bool_only=None, skipna=True, level=None)全ての要素が True の場合に True を返す<-
.any(axis=0, bool_only=None, skipna=True, level=None)ある要素が True の場合に True を返す<-
.argmax(axis=None, skipna=True)要素が最大となる index を返すなし
.argmin(axis=None, skipna=True)要素が最小となる index を返すなし
.astype(dtype, copy=True, errors=’raise’)dtype にて指定する型へキャストする<-
.autocorr(lag=1)指定する要素数のラグを用いた自己相関係数を返すなし
.clip(lower=None, upper=None, axis=None, inplace=False)要素の値を lower から upper の間にトリムする<-
.compare(other, align_axis=1, keep_shape=False, keep_equal=False)元のオブジェクトと other にて指定するオブジェクトを比較したものを返す<-
.corr(method=’pearson’, min_periods=1)なし各カラムどうしの相関係数を返す(method で “pearson”, “kendall”, “spearman” が選択できる)
.copy(deep=True)コピーを作成する.deep=True であれば deep copy を生成<-
.cov(min_periods=None, ddof=1)なしカラムどうしの分散を返す
.describe(percentiles=None, include=None, exclude=None, datetime_is_numeric=False)オブジェクトの統計量を返す<-
.diff(periods=1)行の変化率を返す(period で何行分の差を取るかを指定)<-
.dot(other)other にて指定したオブジェクトとのドット積を返す<-
.drop(labels=None, axis=0, index=None, columns=None, level=None, inplace=False, errors=”raise”)指定した行・列を削除したオブジェクトを返す<-
.drop_duplicates(keep=’first’, inplace=False)重複を削除した Series を返す
.drop_duplicates(subset=None, keep=’first’, inplace=False, ignore_index=False)重複を削除した DataFrame を返す (ignore_index=True にすると返される index がリセットされる)
method-1
メソッドSeriesDataFrame
.dropna(axis=0, inplace=False, how=None)None や NaN を削除したオブジェクトを返す<-
.fillna(value=None, method=None, axis=None, inplace=False, limit=None, downcast=None)NaN を value で指定した値に置換<-
.head(n=5)上位 n 行目までのオブジェクトを返す<-
.idxmax(axis=0, skipna=True)最大となる index を返す<-
.idxmin(axis=0, skipna=True)最小となる index を返す<-
.info(verbose=None, buf=None, max_cols=None, memory_usage=None, show_counts=True)オブジェクトの情報を表示する<-
.interpolate(method=’linear’, axis=0, limit=None, inplace=False, limit_direction=None, limit_area=None, downcast=None)NaN を補間したオブジェクトを返す<-
.isin(values)values で指定した値が要素と同じであれば True, そうでなければ False としたオブジェクトを返す<-
.isna()要素が NaN であれば True, そうでなければ False としたオブジェクトを返す<-
.items()dict.items() のように index と要素のタプルを返すカラム名と pd.Series
.mask(cond, other=nan, inplace=False, axis=None, level=None, errors=NoDefault.no_default, try_cast=NoDefault.no_default)cond にて指定する条件に一致する要素を other にて指定する値に置換したオブジェクトを返す<-
.max(axis=NoDefault.no_default, skipna=True, level=None, numeric_only=None)axis で指定した軸の最大値を返す<-
.mean(axis=NoDefault.no_default, skipna=True, level=None, numeric_only=None)axis で指定した軸の平均値を返す<-
.median(axis=NoDefault.no_default, skipna=True, level=None, numeric_only=None)axis で指定した軸の中央値を返す<-
.min(axis=NoDefault.no_default, skipna=True, level=None, numeric_only=None)axis で指定した軸の最小値を返す<-
.notna()NaN でない要素を True, NaN の要素を False として返す<-
method-2
メソッドSeriesDataFrame
.nunique(dropna=True)重複のない要素の数を返す<-
.rank(axis=0, method=’average’, numeric_only=NoDefault.no_default, na_option=’keep’, ascending=True, pct=False)指定した軸の要素の順序を返す<-
.repeat(repeats, axis=None)元オブジェクトを repeats に指定した回数分繰り返したオブジェクトを返すなし
.replace(to_replace=None, value=NoDefault.no_default, inplace=False, limit=None, regex=False, method=NoDefault.no_default)to_replace で指定した値を value で指定した値に置換したオブジェクトを返す<-
.reset_index(level=None, drop=False, name=NoDefault.no_default, inplace=False)index を振り直したオブジェクトを返す<-
.round(decimals=0)decimals で指定した桁で要素を丸めたオブジェクトを返す<-
.sample(n=None, frac=None, replace=False, weights=None, random_state=None, axis=None, ignore_index=False)指定した axis から n 個のサンプルを取得する<-
.sort_index(axis=0, level=None, ascending=True, inplace=False, kind=’quicksort’, na_position=’last’, sort_remaining=True, ignore_index=False, key=None)index をソートしたオブジェクトを返す<-
.sort_values(ny, axis=0, ascending=True, inplace=False, kind=’quicksort’, na_position=’last’, ignore_index=False, key=None)by で指定したでソートしたオブジェクトを返す<-
.sum(axis=None, skipna=True, level=None, numeric_only=None, min_count=0)axis で指定した軸の総和を返す<-
.tail(n=5)下位 n 行目までのオブジェクトを返す<-
.to_csv(path_or_buf=None, sep=’,’, na_rep=”, float_format=None, columns=None, header=True, index=True, index_label=None, mode=’w’, encoding=None, compression=’infer’, quoting=None, quotechar='”‘, line_terminator=None, chunksize=None, date_format=None, doublequote=True, escapechar=None, decimal=’.’, errors=’strict’, storage_options=None)path_or_buf で指定したファイルに CSV 形式で出力する<-
.to_dict(into=<class ‘dict’>)オブジェクトの辞書型を返す<-
.to_excel(excel_writer, sheet_name=’Sheet1′, na_rep=”, float_format=None, columns=None, header=True, index=True, index_label=None, startrow=0, startcol=0, engine=None, merge_cells=True, encoding=None, inf_rep=’inf’, verbose=True, freeze_panes=None, storage_options=None)path_or_buf で指定した名称の excel ファイルを出力する<-
.to_json(path_or_buf=None, orient=None, date_format=None, double_precision=10, force_ascii=True, date_unit=’ms’, default_handler=None, lines=False, compression=’infer’, index=True, indent=None, storage_options=None)path_or_buf で指定した名称の json ファイルを出力する<-
.to_list()Series をリストに変換して返すなし
.to_numpy(dtype=None, copy=False, na_value=NoDefault.no_default)Series を numpy.ndarray に変換して返すなし
.to_pickle(path, compression=’infer’, protocol=5, storage_options=None).pickle 形式で出力する(compression にてファイル圧縮も可)<-
.unique()重複のない要素の numpy.ndarray を返すなし
.value_counts(normalize=False, sort=True, ascending=False, bins=None, dropna=True)行の数をカウントした結果を返す<-
.where(cond, other=NoDefault.no_default, inplace=False, axis=None, level=None, errors=NoDefault.no_default, try_cast=NoDefault.no_default)cond の条件式に合わない要素以外を NaN としたオブジェクトを返す<-
method-3

メソッドの引数で共通の引数として以下が挙げられ,それぞれ役割があります.

引数意味
axis行もしくは列に対する操作を指定.0: 行,1: 列
levelマルチインデックスに対して有効(今回は取り扱わず)
inplaceメソッド適用後に上書きするかどうかを制御
index行を index で指定するときに用いる
columns列をカラム名で指定するときに用いる
skipnaNaN をスキップして処理するかどうか
condcondition の略で条件式
ascendingTrue だと昇順,False だと降順
parameters of method

上記について,下記で定義する “ser”, “df” を用いて,以下に例を示していきます.

ser = pd.Series(data={"a": 10, "b": -10, "c": 0}, name="series_abc")
ser
# a    10
# b   -10
# c     0
# Name: series_abc, dtype: int64

df = pd.DataFrame(data={"A": [10, -10, 0], "B": [11, 22, 33]})
df
#    A	 B
# 0	 10	11
# 1	-10	22
# 2	  0	33
.abs()
・・・・各要素の絶対値を返す
ser.abs()
# a    10
# b    10
# c     0
# Name: series_abc, dtype: int64

df.abs()
#    A	 B
# 0	10	11
# 1	10	22
# 2	 0	33
.all(axis=0, bool_only=None, skipna=True, level=None)
・・・・全ての要素が True の場合に True を返す
ser.all()
# False

df.all()
# A    False
# B     True
# dtype: bool

df.all(axis=1)
# 0     True
# 1     True
# 2    False
# dtype: bool
.any(axis=0, bool_only=None, skipna=True, level=None)
・・・・ある要素が True の場合に True を返す
ser.any()
# True

df.any()
# A    True
# B    True
# dtype: bool

df.any(axis=1)
# 0    True
# 1    True
# 2    True
# dtype: bool
.argmax(axis=None, skipna=True)
・・・・要素が最大となる index を返す
ser.argmax()
# 0
.argmin(axis=None, skipna=True)
・・・・要素が最小となる index を返す
ser.argmin()
# 1
.astype(dtype, copy=True, errors='raise')
・・・・dtype にて指定する型へキャストする
ser.astype(dtype="float64")
# a    10.0
# b   -10.0
# c     0.0
# Name: series_abc, dtype: float64

df.astype(dtype="float64")
#       A	   B
# 0	 10.0	11.0
# 1	-10.0	22.0
# 2	  0.0	33.0
.autocorr(lag=1)
・・・・指定する要素数のラグを用いた自己相関係数を返す
ser.autocorr()
# -0.9999999999999999

ser.autocorr(lag=0)
# 1.0
.clip(lower=None, upper=None, axis=None, inplace=False)
・・・・要素の値を lower から upper の間にトリムする
ser.clip(lower=1, upper=50)
# a    10
# b     1
# c     1
# Name: series_abc, dtype: int64

df.clip(lower=1, upper=10)
#    A	 B
# 0	10	10
# 1	 1	10
# 2	 1	10
.compare(other, align_axis=1, keep_shape=False, keep_equal=False)
・・・・元のオブジェクトと other にて指定するオブジェクトを比較したものを返す
s1 = pd.Series(["a", "b", "c", "d", "e"])
s2 = pd.Series(["a", "a", "c", "b", "e"])
s1.compare(other=s2)
#   self	other
# 1	   b	    a
# 3	   d	    b

s1.compare(other=s2, align_axis=0)
# 1  self     b
#    other    a
# 3  self     d
#    other    b
# dtype: object

s1.compare(other=s2, keep_shape=True)
#   self	other
# 0	 NaN	  NaN
# 1	   b	    a
# 2	 NaN	  NaN
# 3	   d	    b
# 4	 NaN	  NaN

df
#     A	 B
# 0	 10	11
# 1	-10	22
# 2	  0	33
.corr(method='pearson', min_periods=1)
・・・・各カラムどうしの相関係数を返す(method で "pearson", "kendall", "spearman" が選択できる
df.corr()
#      A	   B
# A	 1.0	-0.5
# B	-0.5	 1.0
.copy(deep=True)
・・・・コピーを作成する.deep=True であれば deep copy を生成
df2 = df.copy()
df2.iat[0,0] = -777
df2.iat[1,1] = -777
df2
#      A	   B
# 0	-777	  11
# 1	 -10	-777
# 2	   0	  33

df.compare(other=df2)
# A	B
#    self	 other  self	 other
# 0	 10.0	-777.0	 NaN	   NaN
# 1	  NaN	   NaN	22.0	-777.0

df.compare(other=df2, align_axis=0)
# A	B
# 0	self	10.0	NaN
# other	-777.0	NaN
# 1	self	NaN	22.0
# other	NaN	-777.0

df.compare(other=df2, keep_shape=True)
#              A	           B
#   self	 other	self	 other
# 0	10.0	-777.0	 NaN	   NaN
# 1	 NaN	   NaN	22.0	-777.0
# 2	 NaN	   NaN	 NaN	   NaN
.cov(min_periods=None, ddof=1)
・・・・カラムどうしの分散を返す
df.cov()
#       A	    B
# A	100.0	-55.0
# B	-55.0	121.0
.describe(percentiles=None, include=None, exclude=None, datetime_is_numeric=False)
・・・・オブジェクトの統計量を返す
ser.describe()
# count     3.0
# mean      0.0
# std      10.0
# min     -10.0
# 25%      -5.0
# 50%       0.0
# 75%       5.0
# max      10.0
# Name: series_abc, dtype: float64

ser.describe(percentiles=[0.1, 0.2, 0.3])
# count     3.0
# mean      0.0
# std      10.0
# min     -10.0
# 10%      -8.0
# 20%      -6.0
# 30%      -4.0
# 50%       0.0
# max      10.0
# Name: series_abc, dtype: float64

df.describe()
#         A	   B
# count	3.0	 3.0
# mean	0.0	22.0
# std	 10.0	11.0
# min	-10.0	11.0
# 25%	 -5.0	16.5
# 50%	  0.0	22.0
# 75%	  5.0	27.5
# max	 10.0	33.0
.diff(periods=1)
・・・・行の変化率を返す(period で何行分の差を取るかを指定)
ser.diff()
# a     NaN
# b   -20.0
# c    10.0
# Name: series_abc, dtype: float64

df.diff()
#       A	   B
# 0	  NaN	 NaN
# 1	-20.0	11.0
# 2	 10.0	11.0

df.diff(periods=2)
#      A	   B
# 0	 NaN	 NaN
# 1	 NaN	 NaN
# 2	-10.0	22.0
.dot(other)
・・・・other にて指定したオブジェクトとのドット積を返す
ser.dot(ser)
# 200

df.shape
# (3, 2)

df.dot(df.T)
#     0	  1	   2
# 0	221	142	 363
# 1	142	584	 726
# 2	363	726	1089

df.T.dot(df)
#      A	   B
# A	 200	-110
# B	-110	1694
.drop(labels=None, axis=0, index=None, columns=None, level=None, inplace=False, errors="raise")
・・・・指定した行・列を削除したオブジェクトを返す
ser.drop(labels=["a", "c"])
# b   -10
# Name: series_abc, dtype: int64

ser.drop(index=["a", "c"])
# b   -10
# Name: series_abc, dtype: int64

存在しない index を指定するとエラーが出ますが,errors に “ignore” をしていすると,指定した index が存在しなくてもエラーが出ず,元のオブジェクトが返されます.

# ser.drop(index=["d"])

# ---------------------------------------------------------------------------
# KeyError                                  Traceback (most recent call last)
# ~\AppData\Local\Temp\ipykernel_14676\1810636668.py in <module>
# ----> 1 ser.drop(index=["d"])

# ~\AppData\Local\Programs\Python\Python39\lib\site-packages\pandas\util\_decorators.py in wrapper(*args, **kwargs)
#     309                     stacklevel=stacklevel,
#     310                 )
# --> 311             return func(*args, **kwargs)
#     312 
#     313         return wrapper

# ~\AppData\Local\Programs\Python\Python39\lib\site-packages\pandas\core\series.py in drop(self, labels, axis, index, columns, level, inplace, errors)
#    4769         dtype: float64
#    4770         """
# -> 4771         return super().drop(
#    4772             labels=labels,
#    4773             axis=axis,

# ~\AppData\Local\Programs\Python\Python39\lib\site-packages\pandas\core\generic.py in drop(self, labels, axis, index, columns, level, inplace, errors)
#    4277         for axis, labels in axes.items():
#    4278             if labels is not None:
# -> 4279                 obj = obj._drop_axis(labels, axis, level=level, errors=errors)
#    4280 
#    4281         if inplace:

# ~\AppData\Local\Programs\Python\Python39\lib\site-packages\pandas\core\generic.py in _drop_axis(self, labels, axis, level, errors, consolidate, only_slice)
#    4321                 new_axis = axis.drop(labels, level=level, errors=errors)
#    4322             else:
# -> 4323                 new_axis = axis.drop(labels, errors=errors)
#    4324             indexer = axis.get_indexer(new_axis)
#    4325 

# ~\AppData\Local\Programs\Python\Python39\lib\site-packages\pandas\core\indexes\base.py in drop(self, labels, errors)
#    6642         if mask.any():
#    6643             if errors != "ignore":
# -> 6644                 raise KeyError(f"{list(labels[mask])} not found in axis")
#    6645             indexer = indexer[~mask]
#    6646         return self.delete(indexer)

# KeyError: "['d'] not found in axis"
ser.drop(index=["d"], errors="ignore")
# a    10
# b   -10
# c     0
# Name: series_abc, dtype: int64

df.drop(index=[0, 2], columns=["A"])
#    B
# 1	22
.drop_duplicates(keep='first', inplace=False)
・・・・重複を削除した Series を返す

ser_tmp = pd.Series(data=["a", "b", "a", "a", "b", "c", "a", "b"])
ser_tmp
# 0    a
# 1    b
# 2    a
# 3    a
# 4    b
# 5    c
# 6    a
# 7    b
# dtype: object

ser_tmp.drop_duplicates()
# 0    a
# 1    b
# 5    c
# dtype: object

ser_tmp.drop_duplicates(keep="last")
# 5    c
# 6    a
# 7    b
# dtype: object

df_tmp = pd.DataFrame(data={"A": [1,0,0], "B": [0,1,0], "C": [0,0,1]})
df_tmp
#   A	B	C
# 0	1	0	0
# 1	0	1	0
# 2	0	0	1

df_tmp.drop_duplicates(subset=["C"])
#   A	B	C
# 0	1	0	0
# 2	0	0	1

df_tmp.drop_duplicates(subset=["C"], ignore_index=True)
#   A	B	C
# 0	1	0	0
# 1	0	0	1
.dropna(axis=0, inplace=False, how=None)
・・・・None や NaN を削除したオブジェクトを返す
import math
import numpy as np
ser_nan = pd.Series(data=[None, 1, pd.NA, math.nan, np.nan, math.nan, np.NaN, np.NAN])
ser_nan
# 0    None
# 1       1
# 2    <NA>
# 3     NaN
# 4     NaN
# 5     NaN
# 6     NaN
# 7     NaN
# dtype: object

ser_nan.dropna()
# 1    1
# dtype: object

df_nan = pd.DataFrame(
    data={
        "A": [1, math.nan, 0],
        "B": [math.nan, math.nan, math.nan],
        "C": [0, math.nan, math.nan],
    },
)
df_nan
#     A	  B	  C
# 0	1.0	NaN	0.0
# 1	NaN	NaN	NaN
# 2	0.0	NaN	NaN

df_nan.dropna()
# A	B	C

df_nan.dropna(how="all")
#     A	  B	  C
# 0	1.0	NaN	0.0
# 2	0.0	NaN	NaN

df_nan.dropna(how="all", axis=1)
#     A	  C
# 0	1.0	0.0
# 1	NaN	NaN
# 2	0.0	NaN

df_nan.dropna(subset=["C"])
#     A	  B	  C
# 0	1.0	NaN	0.0
.fillna(value=None, method=None, axis=None, inplace=False, limit=None, downcast=None)
・・・・NaN を value で指定した値に置換
ser_nan.fillna(value=100)
# 0    100
# 1      1
# 2    100
# 3    100
# 4    100
# 5    100
# 6    100
# 7    100
# dtype: int64

df_nan.fillna(value=100)
#       A	    B	    C
# 0	  1.0	100.0	  0.0
# 1	100.0	100.0	100.0
# 2	  0.0	100.0	100.0
.head(n=5)
・・・・上位 n 行目までのオブジェクトを返す
ser.head()
# a    10
# b   -10
# c     0
# Name: series_abc, dtype: int64

df.head(2)
#     A	 B
# 0	 10	11
# 1	-10	22
.idxmax(axis=0, skipna=True)
・・・・最大となる index を返す
ser.idxmax()
# 'a'

df
#     A	 B
# 0	 10	11
# 1	-10	22
# 2	  0	33

df.idxmax()
# A    0
# B    2
# dtype: int64

df.idxmax(axis=1)
# 0    B
# 1    B
# 2    B
# dtype: object
.idxmin(axis=0, skipna=True)
・・・・最小となる index を返す
ser.idxmin()
# 'b'

df.idxmin()
# A    1
# B    0
# dtype: int64
.info(verbose=None, buf=None, max_cols=None, memory_usage=None, show_counts=True)
・・・・オブジェクトの情報を表示する
ser.info()
# <class 'pandas.core.series.Series'>
# Index: 3 entries, a to c
# Series name: series_abc
# Non-Null Count  Dtype
# --------------  -----
# 3 non-null      int64
# dtypes: int64(1)
# memory usage: 156.0+ bytes

df.info()
# <class 'pandas.core.frame.DataFrame'>
# RangeIndex: 3 entries, 0 to 2
# Data columns (total 2 columns):
#  #   Column  Non-Null Count  Dtype
# ---  ------  --------------  -----
#  0   A       3 non-null      int64
#  1   B       3 non-null      int64
# dtypes: int64(2)
# memory usage: 176.0 bytes
.interpolate(method='linear', axis=0, limit=None, inplace=False, limit_direction=None, limit_area=None, downcast=None)
・・・・NaN を補間
ser_tmp = pd.Series([0, 1, math.nan, 2, 3, math.nan])
ser_tmp.interpolate()
# 0    0.0
# 1    1.0
# 2    1.5
# 3    2.0
# 4    3.0
# 5    3.0
# dtype: float64

df_nan.interpolate()
#     A	  B	  C
# 0	1.0	NaN	0.0
# 1	0.5	NaN	0.0
# 2	0.0	NaN	0.0
.isin(values)
・・・・values で指定した値がオブジェクトに入っていれば True, そうでなければ False を返す(values は set, list, tuple などを受け付け,単一の値は不可)
ser.isin(values=[0])
# a    False
# b    False
# c     True
# Name: series_abc, dtype: bool

df.isin(values=(0, 10))
#       A	    B
# 0	 True	False
# 1	False	False
# 2	 True	False
.isna()
・・・・要素が NaN であれば True, そうでなければ False としたオブジェクトを返す
ser_nan.isna()
# 0     True
# 1    False
# 2     True
# 3     True
# 4     True
# 5     True
# 6     True
# 7     True
# dtype: bool

df_nan.isna()
#       A	   B	    C
# 0	False	True	False
# 1	 True	True	 True
# 2	False	True	 True
Series.items()
・・・・dict.items() のように index と要素のタプルを返す
DataFrame.items()
・・・・カラム名と pd.Series のタプルを返す
for k,v in ser.items():
    print(k, v)
# a 10
# b -10
# c 0

for k,v in df.items():
    print(k)
    print(v)
#       A
# 0    10
# 1   -10
# 2     0
# Name: A, dtype: int64
#       B
# 0    11
# 1    22
# 2    33
# Name: B, dtype: int64
.mask(cond, other=nan, inplace=False, axis=None, level=None, errors=NoDefault.no_default, try_cast=NoDefault.no_default)
・・・・cond にて指定する条件に一致する要素を other にて指定する値に置換したオブジェクトを返す
ser.mask(cond=0 <= ser, other=1)
# a     1
# b   -10
# c     1
# Name: series_abc, dtype: int64

df.mask(cond=0 <= df, other=1)
#     A	B
# 0	  1	1
# 1	-10	1
# 2	  1	1
.max(axis=NoDefault.no_default, skipna=True, level=None, numeric_only=None)
・・・・axis で指定した軸の最大値を返す
ser.max()
# 10

df.max()
# A    10
# B    33
# dtype: int64

df.max(axis=1)
# 0    11
# 1    22
# 2    33
# dtype: int64
.mean(axis=NoDefault.no_default, skipna=True, level=None, numeric_only=None)
・・・・axis で指定した軸の平均値を返す
ser.mean()
# 0.0

df.mean()
# A     0.0
# B    22.0
# dtype: float64

df.mean(axis=1)
# 0    10.5
# 1     6.0
# 2    16.5
# dtype: float64
.median(axis=NoDefault.no_default, skipna=True, level=None, numeric_only=None)
・・・・axis で指定した軸の中央値を返す
ser.median()
# 0.0

df.median()
# A     0.0
# B    22.0
# dtype: float64

df.median(axis=1)
# 0    10.5
# 1     6.0
# 2    16.5
# dtype: float64
.min(axis=NoDefault.no_default, skipna=True, level=None, numeric_only=None)
・・・・axis で指定した軸の最小値を返す
ser.min()
# -10

df.min()
# A   -10
# B    11
# dtype: int64

df.min(axis=1)
# 0    10
# 1   -10
# 2     0
# dtype: int64
.notna()
・・・・NaN でない要素を True, NaN の要素を False として返す
ser_nan.notna()
# 0    False
# 1     True
# 2    False
# 3    False
# 4    False
# 5    False
# 6    False
# 7    False
# dtype: bool

df_nan.notna()
#       A	    B	    C
# 0	 True	False	 True
# 1	False	False	False
# 2	 True	False	False
Series.nunique(dropna=True)
・・・・重複のない要素の数を返す
DataFrame.nunique(axis=0, dropna=True)
・・・・指定した軸の重複のない要素の数を返す
ser.nunique()
# 3

df.nunique()
# A    3
# B    3
# dtype: int64

df.nunique(axis=1)
# 0    2
# 1    2
# 2    2
# dtype: int64
.rank(axis=0, method='average', numeric_only=NoDefault.no_default, na_option='keep', ascending=True, pct=False)
・・・・指定した軸の要素の順序を返す
ser.rank()
# a    3.0
# b    1.0
# c    2.0
# Name: series_abc, dtype: float64

df.rank()
#     A	  B
# 0	3.0	1.0
# 1	1.0	2.0
# 2	2.0	3.0

df.rank(axis=1)
#     A	  B
# 0	1.0	2.0
# 1	1.0	2.0
# 2	1.0	2.0
.repeat(repeats, axis=None)
・・・・元オブジェクトを repeats に指定した回数分繰り返したオブジェクトを返す
ser.repeat(repeats=2)
# a    10
# a    10
# b   -10
# b   -10
# c     0
# c     0
# Name: series_abc, dtype: int64
.replace(to_replace=None, value=NoDefault.no_default, inplace=False, limit=None, regex=False, method=NoDefault.no_default)
・・・・to_replace で指定した値を value で指定した値に置換したオブジェクトを返す
ser.replace(to_replace=10, value=2222)
# a    2222
# b     -10
# c       0
# Name: series_abc, dtype: int64

df.replace(to_replace=10, value=222)
#     A	 B
# 0	222	11
# 1	-10	22
# 2	  0	33
.reset_index(level=None, drop=False, name=NoDefault.no_default, inplace=False)
・・・・index を振り直したオブジェクトを返す
ser.reset_index()
#   index	series_abc
# 0	    a	        10
# 1	    b	       -10
# 2	    c  	       0

df.reset_index()
#   index	  A	 B
# 0	    0	 10	11
# 1	    1	-10	22
# 2	    2	  0	33
.round(decimals=0)
・・・・decimals で指定した桁で要素を丸めたオブジェクトを返す
ser.round(decimals=0)
# a    10
# b   -10
# c     0
# Name: series_abc, dtype: int64

df.round(decimals=0)
#     A	 B
# 0	 10	11
# 1	-10	22
# 2	  0	33
.sample(n=None, frac=None, replace=False, weights=None, random_state=None, axis=None, ignore_index=False)
・・・・指定した axis から n 個のサンプルを取得する
ser.sample(n=2, random_state=0)
# c     0
# b   -10
# Name: series_abc, dtype: int64

df.sample(n=2, random_state=0)
#     A	 B
# 2	  0	33
# 1	-10	22

df.sample(n=1, random_state=0, axis=1)
#    B
# 0	11
# 1	22
# 2	33
.sort_index(axis=0, level=None, ascending=True, inplace=False, kind='quicksort', na_position='last', sort_remaining=True, ignore_index=False, key=None)
・・・・index をソートしたオブジェクトを返す
ser.sort_index()
# a    10
# b   -10
# c     0
# Name: series_abc, dtype: int64

df.sort_index()
#     A	 B
# 0	 10	11
# 1	-10	22
# 2	  0	33
.sort_values(by, axis=0, ascending=True, inplace=False, kind='quicksort', na_position='last', ignore_index=False, key=None)
・・・・指定した index / column でソートしたオブジェクトを返す
ser.sort_values()
# b   -10
# c     0
# a    10
# Name: series_abc, dtype: int64

df.sort_values(by="A")
#     A	 B
# 1	-10	22
# 2	  0	33
# 0	 10	11

df.sort_values(by=0, axis=1, ascending=False)
#    B	  A
# 0	11	 10
# 1	22	-10
# 2	33	  0
.sum(axis=None, skipna=True, level=None, numeric_only=None, min_count=0)
・・・・axis で指定した軸の総和を返す
ser.sum()
# 0

df.sum()
# A     0
# B    66
# dtype: int64

df.sum(axis=1)
# 0    21
# 1    12
# 2    33
# dtype: int64
.tail(n=5)
・・・・下位 n 行目までのオブジェクトを返す
ser.tail()
# a    10
# b   -10
# c     0
# Name: series_abc, dtype: int64

df.tail(2)
#     A	 B
# 1	-10	22
# 2	  0	33
.to_csv(path_or_buf=None, sep=',', na_rep='', float_format=None, columns=None, header=True, index=True, index_label=None, mode='w', encoding=None, compression='infer', quoting=None, quotechar='"', line_terminator=None, chunksize=None, date_format=None, doublequote=True, escapechar=None, decimal='.', errors='strict', storage_options=None)
・・・・path_or_buf で指定したファイルに CSV 形式で出力する
ser.to_csv("series_0.csv")
ser.to_csv("series_1.csv", index=False)
df.to_csv("dataframe_0.csv")
df.to_csv("dataframe_1.csv", index=False)
.to_dict(into=<class 'dict'>)
・・・・オブジェクトの辞書型を返す
ser.to_dict()
# {'a': 10, 'b': -10, 'c': 0}

df.to_dict()
# {'A': {0: 10, 1: -10, 2: 0}, 'B': {0: 11, 1: 22, 2: 33}}
.to_excel(excel_writer, sheet_name='Sheet1', na_rep='', float_format=None, columns=None, header=True, index=True, index_label=None, startrow=0, startcol=0, engine=None, merge_cells=True, encoding=None, inf_rep='inf', verbose=True, freeze_panes=None, storage_options=None)
・・・・path_or_buf で指定した名称の excel ファイルを出力する
ser.to_excel("series.xlsx")
df.to_excel("dataframe.xlsx")
.to_json(path_or_buf=None, orient=None, date_format=None, double_precision=10, force_ascii=True, date_unit='ms', default_handler=None, lines=False, compression='infer', index=True, indent=None, storage_options=None)
・・・・path_or_buf で指定した名称の json ファイルを出力する
ser.to_json("series.json")
df.to_json("dataframe.json", indent=2)
.to_list()
・・・・Series をリストに変換して返す
ser.to_list()
# [10, -10, 0]
.to_numpy(dtype=None, copy=False, na_value=NoDefault.no_default)
・・・・Series を numpy.ndarray に変換して返す
ser.to_numpy()
# array([ 10, -10,   0], dtype=int64)
.to_pickle(path, compression='infer', protocol=5, storage_options=None)
・・・・.pickle 形式で出力する(compression にてファイル圧縮も可)
ser.to_pickle("series.pickle")
df.to_pickle("dataframe.pickle")
df.to_pickle("dataframe.pickle.zip", compression="zip")
.unique()
・・・・重複のない要素の numpy.ndarray を返す
ser_nan.unique()
# array([None, 1, <NA>, nan], dtype=object)
.value_counts(normalize=False, sort=True, ascending=False, bins=None, dropna=True)
・・・・行の数をカウントした結果を返す
ser.value_counts()
#  10    1
# -10    1
#  0     1
# Name: series_abc, dtype: int64

df.value_counts()
#   A   B 
# -10  22    1
#   0  33    1
#  10  11    1
# dtype: int64
.where(cond, other=NoDefault.no_default, inplace=False, axis=None, level=None, errors=NoDefault.no_default, try_cast=NoDefault.no_default)
・・・・cond の条件式に合わない要素以外を NaN としたオブジェクトを返す
ser.where(cond=ser>0)
# a    10.0
# b     NaN
# c     NaN
# Name: series_abc, dtype: float64

df.where(cond=df>0)
#      A	 B
# 0	10.0	11
# 1	 NaN	22
# 2	 NaN	33

pandas の関数

例えば,ライブラリを用いずにファイルを読み書きする場合を考えると,いちいちファイル open / close,または with ブロック内で処理を書く必要がありますが,pandas の関数を用いると,少し複雑な処理を加えて読み込んだりする場合もほぼ 1 ラインでコーディングが可能です.
Series / DataFrame のメソッドとかぶるものも多く,以下では,メソッドにない関数で普段遣いのもののみをまとめていきます.
pandas の関数の一部の一覧は以下で,モノによっては引数の種類が膨大なものもありますが,いつも使う引数は限られているので,普段使う実装を記載します.

関数説明
pd.read_pickle(filepath_or_buffer, compression=’infer’, storage_options=None).pickle ファイルを読み込む
pd.read_csv(filepath_or_buffer, sep=NoDefault.no_default, delimiter=None, header=’infer’, names=NoDefault.no_default, index_col=None, usecols=None, squeeze=None, prefix=NoDefault.no_default, mangle_dupe_cols=True, dtype=None, engine=None, converters=None, true_values=None, false_values=None, skipinitialspace=False, skiprows=None, skipfooter=0, nrows=None, na_values=None, keep_default_na=True, na_filter=True, verbose=False, skip_blank_lines=True, parse_dates=None, infer_datetime_format=False, keep_date_col=False, date_parser=None, dayfirst=False, cache_dates=True, iterator=False, chunksize=None, compression=’infer’, thousands=None, decimal=’.’, lineterminator=None, quotechar='”‘, quoting=0, doublequote=True, escapechar=None, comment=None, encoding=None, encoding_errors=’strict’, dialect=None, error_bad_lines=None, warn_bad_lines=None, on_bad_lines=None, delim_whitespace=False, low_memory=True, memory_map=False, float_precision=None, storage_options=None).csv ファイルを読み込む
pd.read_excel(io, sheet_name=0, header=0, names=None, index_col=None, usecols=None, squeeze=None, dtype=None, engine=None, converters=None, true_values=None, false_values=None, skiprows=None, nrows=None, na_values=None, keep_default_na=True, na_filter=True, verbose=False, parse_dates=False, date_parser=None, thousands=None, decimal=’.’, comment=None, skipfooter=0, convert_float=None, mangle_dupe_cols=True, storage_options=None)excel ファイルを読み込む
pd.read_json(path_or_buf=None, orient=None, typ=’frame’, dtype=None, convert_axes=None, convert_dates=True, keep_default_dates=True, numpy=False, precise_float=False, date_unit=None, encoding=None, encoding_errors=’strict’, lines=False, chunksize=None, compression=’infer’, nrows=None, storage_options=None).json ファイルを読み込む
pd.concat(objs, axis=0, join=’outer’, ignore_index=False, keys=None, levels=None, names=None, verify_integrity=False, sort=False, copy=True)objs にて指定する二つの DataFrame を axis 方向に結合する
function
pd.read_pickle(filepath_or_buffer, compression='infer', storage_options=None)
・・・・.pickle ファイルを読み込む
pd.read_pickle("dataframe.pickle.zip")
#     A	 B
# 0	 10	11
# 1	-10	22
# 2	  0	33
pd.read_csv(filepath_or_buffer, sep=NoDefault.no_default, delimiter=None, header='infer', names=NoDefault.no_default, index_col=None, usecols=None, squeeze=None, prefix=NoDefault.no_default, mangle_dupe_cols=True, dtype=None, engine=None, converters=None, true_values=None, false_values=None, skipinitialspace=False, skiprows=None, skipfooter=0, nrows=None, na_values=None, keep_default_na=True, na_filter=True, verbose=False, skip_blank_lines=True, parse_dates=None, infer_datetime_format=False, keep_date_col=False, date_parser=None, dayfirst=False, cache_dates=True, iterator=False, chunksize=None, compression='infer', thousands=None, decimal='.', lineterminator=None, quotechar='"', quoting=0, doublequote=True, escapechar=None, comment=None, encoding=None, encoding_errors='strict', dialect=None, error_bad_lines=None, warn_bad_lines=None, on_bad_lines=None, delim_whitespace=False, low_memory=True, memory_map=False, float_precision=None, storage_options=None)
・・・・.csv ファイルを読み込む

名前のないカラムは “Unnamed: ?” (? は自動的に 0 から順番に割り当てられる数字)として付与されます.

pd.read_csv("dataframe_0.csv")
#   Unnamed: 0	  A	 B
# 0	         0	 10	11
# 1	         1	-10	22
# 2	         2	  0	33

テーブルデータのヘッダとなるカラム名が無い場合は header=None とします.
また,カラム名としたい行が n 行目にある場合(例えば,.csv ファイルの先頭の数行が設定値の説明が記載されていて飛ばして読み込みたい場合)は header=n-1 とします.

pd.read_csv("dataframe_0.csv", header=None)
#     0	  1	 2
# 0	NaN	  A	 B
# 1	0.0	 10	11
# 2	1.0	-10	22
# 3	2.0	  0	33

pd.read_csv("dataframe_0.csv", header=1)
#   0	 10	11
# 0	1	-10	22
# 1	2	  0	33

読み込んだ後,列名を変更したい場合は,names にリストやタプルでつけたい名称を渡します.

pd.read_csv("dataframe_0.csv", names=("col0", "col1", "col2"))
#   col0 col1	col2
# 0	 NaN	  A	   B
# 1	 0.0	 10	  11
# 2	 1.0	-10	  22
# 3	 2.0	  0	  33

読み込んだ後,行名をどこかの列のデータとしたい場合は,index_col に列名を文字型で与えます.

pd.read_csv("dataframe_0.csv", index_col="A")
#     Unnamed: 0	 B
#   A		
#  10	         0	11
# -10	         1	22
#   0	         2	33

読み込むファイルでいらないカラムがある場合は,読み込みたいカラム名だけを usecols にタプルやリストで渡すと,不要な列が読み込まれません.

pd.read_csv("dataframe_0.csv", usecols=["A", "B"])
#     A	 B
# 0	 10	11
# 1	-10	22
# 2	  0	33
pd.read_excel(io, sheet_name=0, header=0, names=None, index_col=None, usecols=None, squeeze=None, dtype=None, engine=None, converters=None, true_values=None, false_values=None, skiprows=None, nrows=None, na_values=None, keep_default_na=True, na_filter=True, verbose=False, parse_dates=False, date_parser=None, thousands=None, decimal='.', comment=None, skipfooter=0, convert_float=None, mangle_dupe_cols=True, storage_options=None)
・・・・excel ファイルを読み込む

sheet_name にシート名を指定することができ,整数型だとシートの何枚目か,文字型だとシート名を与えることで,読み込むシートを指定できます.
後の引数の扱い方は read_csv とほとんど同じです.

pd.read_excel("dataframe.xlsx", sheet_name=0, index_col=0)
#     A	 B
# 0	 10	11
# 1	-10	22
# 2	  0	33
pd.read_json(path_or_buf=None, orient=None, typ='frame', dtype=None, convert_axes=None, convert_dates=True, keep_default_dates=True, numpy=False, precise_float=False, date_unit=None, encoding=None, encoding_errors='strict', lines=False, chunksize=None, compression='infer', nrows=None, storage_options=None)
・・・・.json ファイルを読み込む
pd.read_json("./dataframe.json")
#     A	 B
# 0	 10	11
# 1	-10	22
# 2	  0	33
pd.concat(objs, axis=0, join='outer', ignore_index=False, keys=None, levels=None, names=None, verify_integrity=False, sort=False, copy=True)
・・・・objs にて指定する二つの DataFrame を axis 方向に結合する
pd.concat(objs=[df, df_nan], axis=0)
#       A	   B	  C
# 0	 10.0	11.0	NaN
# 1	-10.0	22.0	NaN
# 2	  0.0	33.0	NaN
# 0	  1.0	 NaN	0.0
# 1	  NaN	 NaN	NaN
# 2	  0.0	 NaN	NaN

pd.concat(objs=[df, df_nan], axis=1)
#     A	 B	  A	  B	  C
# 0	 10	11	1.0	NaN	0.0
# 1	-10	22	NaN	NaN	NaN
# 2	  0	33	0.0	NaN	NaN

演習問題

  • Q.1: フリーの花のアヤメの分類データセットを一つの pandas.DataFrame として定義し,表示させましょう.(https://raw.githubusercontent.com/mwaskom/seaborn-data/master/iris.csv にアクセスいただき,web ページ上で右クリックし,メニューから 名前をつけて保存 でローカルに .csv ファイルとして保存できます.scikit-learn がインストール済みであれば datasets.load_iris() でも読み込み可能ですが,その場合は,目的変数のカラム名を “species” とし,目的変数の要素をアヤメの品種も文字列に置き換えてください.)
  • Q.2: 説明変数の sepal は花のがく片,petal は花の花弁を表します.上記で生成した DataFrame に,例えば次の特徴量を追加してみましょう.
    • がく片を長方形と近似し,”sepal length (cm)” と “sepal width (cm)” を用いて “sepal area (cm^2)” という特徴量を追加しましょう.
    • 花弁を長方形と近似し,”petal length (cm)” と “petal width (cm)” を用いて “petal area (cm^2)” という特徴量を追加しましょう.
  • Q.3: 上記で生成した DataFrame について,説明変数の各カラムの主要統計量を一行で出してみましょう.
  • Q.4: 説明変数の各カラムの主要統計量について,品種別 (“species” ごと) で見てみましょう.ここで,DataFrame の df における “species” カラムの値が “setosa” である部分を抜き取るためには,df[df["species"]=="setosa"] とすることで,条件にマッチした DataFrame が返されます.品種の種類は set(df(["species"])) にて確認できます.
  • Q.5: 説明変数の相関係数行列を一行で出してみましょう.
  • Q.6: 追加した特徴量の “sepal area (cm^2)” はあまり意味がなさそうなので,このカラムを削除しましょう.
  • Q.7: 上記まで作成していた DataFrame を別名でコピーしてください.
  • Q.8: コピーした DataFrame について,目的変数の “species” 以外のカラムについて 0 ~ 1 へ正規化してください.ここで正規化とは,各カラムの値が最小値 0,最大値 1 へリスケーリングさせることを言い,数列 \(X\) に対し \(i\) 番目の要素 \(x_i\) とすると,要素の最大値 \(x_{max}\) と最小値 \(x_{min}\) を用いて,正規化後の \(i\) 番目の要素の値 \(x_i^+\) は,次で示すことができます.

$$
x_i^+ = \frac{x_i – x_{min}}{x_{max} – x_{min}}
$$

  • Q.9: 正規化後の DataFrame について,データの 75 % の行をランダムに抜き取った DataFrame を新たな変数 train に格納し,残りの 25 % の行の DataFrame を新たな変数 test に格納しましょう.
  • Q.10: Q.9 にて作成した train, test を pickle 形式かつ圧縮して保存しましょう.

演習問題の解答

  • Q.1: フリーの花のアヤメの分類データセットを一つの pandas.DataFrame として定義し,表示させましょう.(https://raw.githubusercontent.com/mwaskom/seaborn-data/master/iris.csv にアクセスいただき,web ページ上で右クリックし,メニューから 名前をつけて保存 でローカルに .csv ファイルとして保存できます.scikit-learn がインストール済みであれば datasets.load_iris() でも読み込み可能ですが,その場合は,目的変数のカラム名を “species” とし,目的変数の要素をアヤメの品種も文字列に置き換えてください.)
import pandas as pd

読み込み自体は,次の try ブロック,もしくは,except ブロックどちらでも問題ありません.

try:
    from sklearn.datasets import load_iris
    iris = load_iris()
    print(iris.keys())
    df = pd.DataFrame(
        data=iris["data"],
        columns=iris["feature_names"],
    )
    df["species"] = [iris["target_names"][i] for i in iris["target"]]
except Exception:
    df = pd.read_csv(r"問題の手順で web からダウンロードしてきた iris.csv の絶対パス")
df.tail(3)
# dict_keys(['data', 'target', 'frame', 'target_names', 'DESCR', 'feature_names', 'filename'])
#      sepal length (cm)  sepal width (cm)  petal length (cm)  petal width (cm)  \
# 0                  5.1               3.5                1.4               0.2   
# 1                  4.9               3.0                1.4               0.2   
# 2                  4.7               3.2                1.3               0.2   
# 3                  4.6               3.1                1.5               0.2   
# 4                  5.0               3.6                1.4               0.2   
# ..                 ...               ...                ...               ...   
# 145                6.7               3.0                5.2               2.3   
# 146                6.3               2.5                5.0               1.9   
# 147                6.5               3.0                5.2               2.0   
# 148                6.2               3.4                5.4               2.3   
# 149                5.9               3.0                5.1               1.8   
# 
#        species  
# 0       setosa  
# 1       setosa  
# 2       setosa  
# 3       setosa  
# 4       setosa  
# ..         ...  
# 145  virginica  
# 146  virginica  
# 147  virginica  
# 148  virginica  
# 149  virginica  
# 
# [150 rows x 5 columns]
  • Q.2: 説明変数の sepal は花のがく片,petal は花の花弁を表します.上記で生成した DataFrame に,例えば次の特徴量を追加してみましょう.
    • がく片を長方形と近似し,”sepal length (cm)” と “sepal width (cm)” を用いて “sepal area (cm^2)” という特徴量を追加しましょう.
    • 花弁を長方形と近似し,”petal length (cm)” と “petal width (cm)” を用いて “petal area (cm^2)” という特徴量を追加しましょう.
df["sepal area (cm^2)"] = df["sepal length (cm)"] * df["sepal width (cm)"]
df["petal area (cm^2)"] = df["petal length (cm)"] * df["petal width (cm)"]
print(df.tail(3))
#      sepal length (cm)  sepal width (cm)  petal length (cm)  petal width (cm)  \
# 147                6.5               3.0                5.2               2.0   
# 148                6.2               3.4                5.4               2.3   
# 149                5.9               3.0                5.1               1.8   
# 
#        species  sepal area (cm^2)  petal area (cm^2)  
# 147  virginica              19.50              10.40  
# 148  virginica              21.08              12.42  
# 149  virginica              17.70               9.18  
  • Q.3: 上記で生成した DataFrame について,説明変数の各カラムの主要統計量を一行で出してみましょう.
print(df.describe())
#        sepal length (cm)  sepal width (cm)  petal length (cm)  \
# count         150.000000        150.000000         150.000000   
# mean            5.843333          3.057333           3.758000   
# std             0.828066          0.435866           1.765298   
# min             4.300000          2.000000           1.000000   
# 25%             5.100000          2.800000           1.600000   
# 50%             5.800000          3.000000           4.350000   
# 75%             6.400000          3.300000           5.100000   
# max             7.900000          4.400000           6.900000   
# 
#        petal width (cm)  sepal area (cm^2)  petal area (cm^2)  
# count        150.000000         150.000000         150.000000  
# mean           1.199333          17.822867           5.794067  
# std            0.762238           3.361854           4.712390  
# min            0.100000          10.000000           0.110000  
# 25%            0.300000          15.660000           0.420000  
# 50%            1.300000          17.660000           5.615000  
# 75%            1.800000          20.325000           9.690000  
# max            2.500000          30.020000          15.870000  
  • Q.4: 説明変数の各カラムの主要統計量について,品種別 (“species” ごと) で見てみましょう.ここで,DataFrame の df における “species” カラムの値が “setosa” である部分を抜き取るためには,df[df["species"]=="setosa"] とすることで,条件にマッチした DataFrame が返されます.品種の種類は set(df(["species"])) にて確認できます.
species = set(df["species"])
print(species)
# {'virginica', 'versicolor', 'setosa'}

print(df[df["species"]=="setosa"].describe())
#        sepal length (cm)  sepal width (cm)  petal length (cm)  \
# count           50.00000         50.000000          50.000000   
# mean             5.00600          3.428000           1.462000   
# std              0.35249          0.379064           0.173664   
# min              4.30000          2.300000           1.000000   
# 25%              4.80000          3.200000           1.400000   
# 50%              5.00000          3.400000           1.500000   
# 75%              5.20000          3.675000           1.575000   
# max              5.80000          4.400000           1.900000   
# 
#        petal width (cm)  sepal area (cm^2)  petal area (cm^2)  
# count         50.000000          50.000000          50.000000  
# mean           0.246000          17.257800           0.365600  
# std            0.105386           2.933775           0.181155  
# min            0.100000          10.350000           0.110000  
# 25%            0.200000          15.040000           0.280000  
# 50%            0.200000          17.170000           0.300000  
# 75%            0.300000          19.155000           0.420000  
# max            0.600000          25.080000           0.960000  

print(df[df["species"]=="versicolor"].describe())
#        sepal length (cm)  sepal width (cm)  petal length (cm)  \
# count          50.000000         50.000000          50.000000   
# mean            5.936000          2.770000           4.260000   
# std             0.516171          0.313798           0.469911   
# min             4.900000          2.000000           3.000000   
# 25%             5.600000          2.525000           4.000000   
# 50%             5.900000          2.800000           4.350000   
# 75%             6.300000          3.000000           4.600000   
# max             7.000000          3.400000           5.100000   
# 
#        petal width (cm)  sepal area (cm^2)  petal area (cm^2)  
# count         50.000000          50.000000          50.000000  
# mean           1.326000          16.526200           5.720400  
# std            0.197753           2.866882           1.368403  
# min            1.000000          10.000000           3.300000  
# 25%            1.200000          14.347500           4.860000  
# 50%            1.300000          16.385000           5.615000  
# 75%            1.500000          18.495000           6.750000  
# max            1.800000          22.400000           8.640000  

print(df[df["species"]=="virginica"].describe())
# count           50.00000         50.000000          50.000000   
# mean             6.58800          2.974000           5.552000   
# std              0.63588          0.322497           0.551895   
# min              4.90000          2.200000           4.500000   
# 25%              6.22500          2.800000           5.100000   
# 50%              6.50000          3.000000           5.550000   
# 75%              6.90000          3.175000           5.875000   
# max              7.90000          3.800000           6.900000   
# 
#        petal width (cm)  sepal area (cm^2)  petal area (cm^2)  
# count          50.00000          50.000000          50.000000  
# mean            2.02600          19.684600          11.296200  
# std             0.27465           3.458783           2.157412  
# min             1.40000          12.250000           7.500000  
# 25%             1.80000          17.430000           9.717500  
# 50%             2.00000          20.060000          11.445000  
# 75%             2.30000          21.412500          12.790000  
# max             2.50000          30.020000          15.870000  

3 品種の主要統計量をそれぞれ見比べると,”virginica” が sepal length, petal length / width が大きいことが分かります.
また,”setosa” は他の2品種に比べて petal width / length が極端に小さいことが分かります.

  • Q.5: 説明変数の相関係数行列を一行で出してみましょう.
print(df.corr())
#                    sepal length (cm)  sepal width (cm)  petal length (cm)  \
# sepal length (cm)           1.000000         -0.117570           0.871754   
# sepal width (cm)           -0.117570          1.000000          -0.428440   
# petal length (cm)           0.871754         -0.428440           1.000000   
# petal width (cm)            0.817941         -0.366126           0.962865   
# sepal area (cm^2)           0.679180          0.643461           0.360909   
# petal area (cm^2)           0.857300         -0.288431           0.958422   
# 
#                    petal width (cm)  sepal area (cm^2)  petal area (cm^2)  
# sepal length (cm)          0.817941           0.679180           0.857300  
# sepal width (cm)          -0.366126           0.643461          -0.288431  
# petal length (cm)          0.962865           0.360909           0.958422  
# petal width (cm)           1.000000           0.368845           0.980333  
# sepal area (cm^2)          0.368845           1.000000           0.454503  
# petal area (cm^2)          0.980333           0.454503           1.000000  
  • sepal length, petal length / width はそれぞれ相関が大きいことが示されます.
  • sepal width は他の説明変数に対する相関は大きくありません.
  • sepal area ですが,他の説明変数との相関も高くなく,追加しましたがあまり意味はなさそうです.
  • Q.6: 追加した特徴量の “sepal area (cm^2)” はあまり意味がなさそうなので,このカラムを削除しましょう.
df.drop(columns="sepal area (cm^2)", inplace=True)
print(df.tail(3))
#      sepal length (cm)  sepal width (cm)  petal length (cm)  petal width (cm)  \
# 147                6.5               3.0                5.2               2.0   
# 148                6.2               3.4                5.4               2.3   
# 149                5.9               3.0                5.1               1.8   
# 
#        species  petal area (cm^2)  
# 147  virginica              10.40  
# 148  virginica              12.42  
# 149  virginica               9.18  
  • Q.7: 上記まで作成していた DataFrame を別名でコピーしてください.
df_new = df.copy()
  • Q.8: コピーした DataFrame について,目的変数の “species” 以外のカラムについて 0 ~ 1 へ正規化してください.ここで正規化とは,各カラムの値が最小値 0,最大値 1 へリスケーリングさせることを言い,数列 \(X\) に対し \(i\) 番目の要素 \(x_i\) とすると,要素の最大値 \(x_{max}\) と最小値 \(x_{min}\) を用いて,正規化後の \(i\) 番目の要素の値 \(x_i^+\) は,次で示すことができます.

$$
x_i^+ = \frac{x_i – x_{min}}{x_{max} – x_{min}}
$$

def normalize(dataframe, column):
    dataframe[column] = (
        (dataframe[column] - dataframe[column].min())
        / (dataframe[column].max() - dataframe[column].min())
    )
    return dataframe[column]


df_new["sepal length (cm)"] = normalize(dataframe=df_new, column="sepal length (cm)")
df_new["sepal width (cm)"] = normalize(dataframe=df_new, column="sepal width (cm)")
df_new["petal length (cm)"] = normalize(dataframe=df_new, column="petal length (cm)")
df_new["petal width (cm)"] = normalize(dataframe=df_new, column="petal width (cm)")
df_new["petal area (cm^2)"] = normalize(dataframe=df_new, column="petal area (cm^2)")
print(df_new.tail(3))
#      sepal length (cm)  sepal width (cm)  petal length (cm)  petal width (cm)  \
# 147           0.611111          0.416667           0.711864          0.791667   
# 148           0.527778          0.583333           0.745763          0.916667   
# 149           0.444444          0.416667           0.694915          0.708333   
# 
#        species  petal area (cm^2)  
# 147  virginica           0.652919  
# 148  virginica           0.781091  
# 149  virginica           0.575508  
  • Q.9: 正規化後の DataFrame について,データの 75 % の行をランダムに抜き取った DataFrame を新たな変数 train に格納し,残りの 25 % の行の DataFrame を新たな変数 test に格納しましょう.
train = df_new.sample(n=int(len(df_new) * 0.75), random_state=42, axis=0)
print(train.tail(3))
#      sepal length (cm)  sepal width (cm)  petal length (cm)  petal width (cm)  \
# 63            0.500000          0.375000           0.627119          0.541667   
# 54            0.611111          0.333333           0.610169          0.583333   
# 126           0.527778          0.333333           0.644068          0.708333   
# 
#         species  petal area (cm^2)  
# 63   versicolor           0.410533  
# 54   versicolor           0.430838  
# 126   virginica           0.541244  

test = df_new.drop(index=train.index)
print(test.tail(3))
#      sepal length (cm)  sepal width (cm)  petal length (cm)  petal width (cm)  \
# 144           0.666667          0.541667           0.796610          1.000000   
# 147           0.611111          0.416667           0.711864          0.791667   
# 149           0.444444          0.416667           0.694915          0.708333   
# 
#        species  petal area (cm^2)  
# 144  virginica           0.897208  
# 147  virginica           0.652919  
# 149  virginica           0.575508  
  • Q.10: Q.9 にて作成した train, test を pickle 形式かつ圧縮して保存しましょう.
train.to_pickle("./train.pickle.gz", compression="gzip")
test.to_pickle("./test.pickle.gz", compression="gzip")

Python のおすすめの学習方法

プログラミングを最短で習得する,少なくても自分の意志で使えるようになる方法について,いくつかプログラミング言語を触ってきた筆者としては何の言語においても,以下2点が重要だと思います.

  • 元々自分が他の言語で作っていた処理を違う言語で書き直す・・・・英語を勉強するときも,脳を生まれたばかりのまっさらな状態から勉強するわけではなく,日本語を通したり対比して,学習済みの言語野を用いて勉強するのと似ています
  • 言語自体を網羅的に勉強するのではなく,やりたい事を先に考え,それを達成するために色々と調べながら実装する・・・・例えば,留学で語学力が上達するのは,その国の言葉を使ってコミュニケーションを取ることが強制されるためであり,使うことに対するモチベーションが一番大事です

独学で行うには,やはり2点目の「やりたい事ドリブン学習」が効果的で,例えば次の書籍は,Python を流行らせている AI/データ分析/機械学習/深層学習について実装することに主眼を置き説明されているので,実際に手を動かしながら学んでいける本だと思います(筆者も最初にこちらの書籍で遊びながら学びました).

コメント

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