Pandas 20本ノック
この記事は今後更新する可能性があります。
0 はじめに・準備
Pandasは,Pythonにおいて表形式データを扱うための拡張モジュールである。
ここでは,Pandasに慣れるための問題20問を紹介する。
準備として,必要なモジュール・データをインポートしておこう(コピペでよい)。
#コピペでOK import pandas as pd import numpy as np import matplotlib.pyplot as plt from sklearn.datasets import load_iris _iris = load_iris() df_data = pd.DataFrame(_iris.data, columns=["がく片の長さ","がく片の幅","花びらの長さ","花びらの幅"]) df_target = pd.DataFrame(_iris.target, columns=["花の種類"]) df = pd.concat([df_data,df_target], axis=1)
1 基本的な操作と可視化(1〜10本目)
データの確認
ノック1 取得したデータ $\rm df$ の先頭5行,末尾10行を表示せよ。
【解答】
#先頭5行を表示 df.head() #末尾10行を表示 df.tail(10)
表の一部を抽出①
ノック2 データ $\rm df$ のインデックス100〜110に該当する行,「がく片の幅」「花の種類」列を抽出せよ。
【解答】
df.loc[100:110, ['がく片の幅','花の種類']]
表の一部を抽出②
ノック3 データ $\rm df$ の上から100〜110行目,2〜4列目のみを抽出せよ。
【解答】
#ilocを用いる場合 df.iloc[99:110,1:4] #locを用いる場合 df.loc[100:110,'がく片の幅':'花びらの幅']
補足 loc
は列を「番号」ではなく「カラム名」で取得する。また行については,入力したインデックスの番号をそのまま出力する(仮にインデックスの順番がバラバラでも,iloc
は上から順番に取得するが,loc
はインデックス番号に忠実に取得する)。
普段はiloc
を用いておき,loc
を見たらインデックスの順番が異なると覚えておこう。
条件抽出
ノック4 データ $\rm df$ のうち「がく片の幅が3以上,かつ花びらの長さが6以上」のデータをすべて抽出せよ。
【解答】
df[(df['がく片の幅'] >= 3) & (df['花びらの長さ'] >= 6)]
補足 Pythonでは論理記号はand
,or
,not
を使うのが普通だが,Pandasではこれは使えないことに注意しよう。Pandasではこれらに対応するものは&
,|
,~
である。
カラム名の変更
ノック5 データ $\rm df$ の「花の種類」列を「花の名前」に変更せよ。
(あくまで一時的な問題のためなので,変更後は名前をもとに戻しておくこと)。
【解答】
df.rename(columns={'花の種類':'花の名前'})
ユニークな値の抽出
ノック6 データ $\rm df$ の「花の種類」列のうち,ユニークな値を抽出せよ(つまり,データに含まれる「花の種類」をすべて列挙せよ)。また,それぞれに当てはまるデータの個数をカウントせよ。
【解答】
#ユニークな値の抽出 df['花の種類'].unique() #それぞれのデータの個数のカウント df['花の種類'].value_counts()
並び替え
ノック7 データ $\rm df$ を「がく片の長さ」の高い順に並び替えよ。
【解答】
df.sort_values('がく片の長さ', ascending=False) #各データのインデックスはそのままになっていることに注意する。
グループごとの集計
ノック8 データ $\rm df$ を「花の種類」ごとにグループ分けし,それぞれのカラムの平均値を求めよ。
【解答】
df.groupby('花の種類').mean()
平均・分散・相関係数
ノック9 データ $\rm df$ の各列での平均と標準偏差を求めよ。また,各列間の相関係数を確認せよ。
【解答】
#平均と分散 df.mean() df.std() #相関係数 df.corr()
散布図でのデータ表示
ノック10 ノック9によれば,データ $\rm df$ には「花びらの長さ」と「花びらの幅」に強い正の相関があることが分かる。実際にこれを散布図を作って確認せよ。
【解答】
df.plot.scatter(x='花びらの長さ', y='花びらの幅') #日本語が表示できないことでエラーが生じるが,気にしないことにする
2 データの作成と結合(11〜15本目)
データの作成
ノック11 データ $\rm df1$ を,下記のように作成せよ。
- 列は「花の種類」「花の名前」の $2$ つである。
- 行は $3$ つあり,中身はそれぞれ「0, "setona"」「1, "versicolor"」「2, "virginica"」である。
- 「花の種類」列は,
int
型となるようにすること。
【解答1】
#1つずつ,行を追加していく方法。可読性が高いが,計算速度が遅い df1 = pd.DataFrame(columns=["花の種類", "花の名前"]) # 行を追加(ilocは使えないので注意) df1.loc[len(df1)] = [0, "setona"] df1.loc[len(df1)] = [1, "versicolor"] df1.loc[len(df1)] = [2, "virginica"] df1
【解答2】
#リストの中に辞書型を入れて,それを変換する方法。一括で作るので計算速度が早い data = [ {"花の種類": 0, "花の名前": "setona"}, {"花の種類": 1, "花の名前": "versicolor"}, {"花の種類": 2, "花の名前": "virginica"} ] df1 = pd.DataFrame(data) df1
補足 この他に,numpyで行列を作り,それをDataFlame型に変換する方法もあるが,結果がすべてobject型になってしまう等の課題があり一般的でないので,おすすめしない。
データの結合
ノック12 データ $\rm df$ に $\rm df1$ を左外部結合せよ。結果を $\rm df2$ とせよ。
【解答】
df2 = pd.merge(df, df1, on = '花の種類', how = 'left') df2
補足 データを結合するその他の方法として,concat
メソッドがある。ただしこれは高度なことを考えずに,たんに $2$ つの表を「くっつける」感覚に近い。たとえばCSVファイルが $2$ つに分かれていて,それを機械的にくっつける場合である。
ダミー変数への変換
ノック13 データ $\rm df2$ の「花の名前」をダミー変数に変換せよ。
【解答】
pd.get_dummies(df2, columns=['花の名前'])
2 欠損値の扱い(11〜15本目)
欠損値とは?
まず,欠損値には $2$ 種類あることに注意しよう。$1$ つ目はPythonで標準で与えられているNone
で,$2$ つ目はfloat型で「非数」を表すnan
(NaN
やNan
と表示されることもあるが,全部同じ)である。
PythonでCSVを読み込むと欠損値はすべてnan
へ変換されるので,我々が今後注目すべき欠損値はnan
である。
補足 他にも,空の文字列''
も欠損値と呼ぶこともある(が,ここでは扱わない)。これはPandasでは何も表示されない。
ノック14 データnan
とNone
をそれぞれ作成せよ。
【解答】
#Noneはそのまま打つことで作れる None #nanの作り方は,おもに2つある。 float('nan') #nanの大文字・小文字は自由。NaN等でも良い np.nan
欠損値の列を追加
ノック15 データ $\rm df$ に $2$ つの新しい列「欠損値1」「欠損値2」を作成し,それぞれの列をnan
とNone
で埋めよ。結果を $\rm df3$ とすること。
【解答】
_df3 = df _df3['欠損値1'] = np.nan df3 = _df3 df3['欠損値2'] = None df3
欠損値の行を追加
ノック16 データ $\rm df3$ に 対し,すべての列がnan
の行を追加せよ。
【解答】
df3.loc[len(df)] = [np.nan for i in range(7)] df3 # 7は列数。取得しても良い
欠損値の個数を確認する
ノック17 データ $\rm df3$ の各列における欠損値の個数を集計せよ。
【解答】
df3.isnull().sum()
ノック18 データ $\rm df3$ のすべての欠損値を $0$ で埋めよ。
【解答】
df3.fillna(0)
ノック19 データ $\rm df3$ の欠損値が存在するすべての列を削除せよ。
【解答】
df3.dropna(axis=1)