はてだBlog(仮称)

私的なブログど真ん中のつもりでしたが、気づけばWebサイト系のアプリケーション開発周りで感じたこと寄りの自分メモなどをつれづれ述べています。2020年6月現在、Elasticsearch、pandas、CMSなどに関する話題が多めです。...ですが、だんだんとより私的なプログラムのスニペット置き場になりつつあります。ブログで述べている内容は所属組織で販売している製品などに関するものではなく、また所属する組織の見解を代表するものではありません。

pandasクックブックの感想を借りた自分メモ

pandasクックブックの部分的な感想

この記事は、こちら↓の書籍の読書感想文です。

pandasクックブック ―Pythonによるデータ処理のレシピ―

pandasの理解が深まるとともに、他では見られない、暗黙のルール(ではないんだろうが私は良くわかってなかったpandasの世界観)が まとまっていて、非常にためになりました。

腹落ちする書籍でした。

なお、書籍は体系的かつ実践的な構成になっていると思いますが、以下は読書時に私が知らなかったことや面白いと思ったことをピックアップしたので、散発的です。 (宣伝になってなかったらごめんなさい... > オーサーの方、訳者の方 )

また、時々私的な見解が混ざっているところがあります。その点に関しては読書感想文ということでご容赦ください。


なお、書籍のもう一つのよいところは、実データなどがひととおりダウンロードできることです。

例えばこちら↓

github.com

この記事の見出し(※構造化されていません)


Pandas基礎など

DataFrameの3要素 インデックス、カラム、データ index, columns, values

>type(df.index)
>     class 'pandas.core.indexes.range.RangeIndex'
> type(df.columns)
>     class 'pandas.core.indexes.base.Index'>
> type(df.values)
>  class 'numpy.ndarray'>
> 

RangeIndexはサブクラスであることを実感

issubclass(pd.RangeIndex, pd.Index)

RangeIndexは必要になるまではメモリにロードされない

p.6 、p.31 に記載の「型の話」

これらのページには普段雰囲気で使っている(※よい子は真似しないようにちゃんと型を理解しましょう。)pandasのDataFrameやSeriesの1セル*1のデータ型に関してまとめてある。 直接の引用は憚られるので、各ページに何の表が書いてあるかだけ示す。 なんとなく、astypeやselect_dtypesが分かったきになる。

p.6 各種データ型とNumPy/pandasオブジェクト、pandas文字列名などの対応表が記載

p.31 Pythonオブジェクトと型を表す文字列

df.dtypes

color                         object
director_name                 object
num_critic_for_reviews       float64
duration                     float64
director_facebook_likes      float64
...
>> df.get_dtype_counts()
float64    13
int64       3
object     12
dtype: int64
>>> 

>> df.select_dtypes()

各カラムのデータ型
df = pd.read_csv('data/movie.csv')

メソッドなどを手軽(?)に確認
dir(pd.Series)

カウント

(以下、srはSeriesのデータ)

sr.size sr.shape, len(sr)

sr.count() 非欠損値のカウント

nunique() ............

sr.describe()

sr.fillna(0) 欠損値を0にセットする
sr.dropna() 欠損値を削除

ブロードキャスト sr + 1

Booleanインデックス

sr > 7True FalseのSeriesを戻す

Pythonの特殊メソッドによって演算子が実現されているのでいろいろできる。

また、mul、addなど具体的なメソッドもある。

◆インデックスとして明示的に特定のカラムを用いる

df.set_index('インデックスにしたいカラム名')

◆カラムをメソッドで選択する...など

sr.all()
sr.any() ※ df.any().any()
sr.isnull() ※欠損値を抜き出す
sr.head()
sr.select_dtypes(include=['int']).head()
sr.filter(like='foo')
sr.filter(regex='\d')
sr.filter(items=['カラム名1','カラム名2'])
 ※インデックス演算子と同じ動きだが、KeyErrorにならない。

Pandasの欠損値

 NumPyのNaNオブジェクト(np.nan) ※ np.nan == np.nan → Falseとなることに注意

◆欠損値を含むDataFrameを比較する場合は、equalsメソッドを使う  eqメソッドとの違いもチェック。

◆メモリ使用量の確認

df.memory_usage(deep=True) →濃度が低いデータの型をカテゴリ型に変換する

◆ df['foo'] = df['foo'].astype('category)

◆よくあるランキング

nsmallest
nlargest
sort_values
drop_duplicates ※keepパラメータ
cummax
cummin
cumsum
※他にも累積値系のメソッドがいくつかあるので活用したいところ

◆ iloc、loc 定番だが、周期的に値を取り出す...といったことがやりやすいと捉えると、df['aaa']の形式といい感じで棲み分けられる気がした。

また、スライス表記(df[1:5]のようなコロンを使ったやつ)はいろいろできて便利(だが、ぱっと見よくわからん)。

◆ iat、atはスカラー値専門。その分、loc系よりも高速。

◆p.85

clip_lower clip_upper clip idmax

hxn.blog.jp


Booleanインデックス法

Booleanインデックス法/Boolean選択 (およびこれらの対象カラムにインデックスを用いるインデックス選択)

df.colname > 8 df['colname'] > 8 →True, FalseのSeriesが得られる

論理演算は、Pythonの「and, or , not」ではなく、「&,|,~」 を使う。

df.colname > 8 | df.colname < 5

この章の後半には、SQLの代用というワークショップのセクションがあって、いろいろテクニックを駆使する様がおもしろい。

query、where、maskメソッド (queryは、Booleanインデックス法を読みやすさ改善するものだととらえてよい。 ちなみに、@varname など@をつけてPython変数を参照することもできる)


インデックスアラインメント

これまた雰囲気で理解していたpandasのインデックスアライメントの特徴がまとめられて参考になる。 この章の末尾の演習などで実際の性質を確かめておくと非常に勉強になりそう。

... ので気になる人はぜひ書籍を読んでください。

ここでは、インデックスアラインメントではなく、途中に紹介のあった、Indexオブジェクトに関する演算などに関して、こんなこともできるよというところのメモ

◆Indexオブジェクトに算術演算子や比較演算が可能 →これらを使えば機械的に名称を変更できる

df.columns + '_A'

df.columns > 'G'

Seriesやndarrayと同じような演算ができる。

和、積、差、対称差などの集合演算も可能

union, symmetric_difference...
difference

addメソッドは加算演算子(+)と同様。
ただし、fill_valueパラメータで非合致インデックスを処理できる(便利!)

Groupby

◆直接groupbyオブジェクトにメソッドチェイニングできる集約関数

min,max,mean,median,sum,count,std,var,size,describe,nunique,idxmin,idxmax

◆p.153

aggメソッドを使って複数カラムを集約すると2階層のインデックスオブジェクト が作られる。集約からカラムが上、集約関数が下。

◆ p.150

グループ分け時のMultiIndex解消

◆イディオム

df.columns = df.get_level_values(0) + '_' + df.get_level_values(1)
の後に、reset_index()

◆集約関数は *args、**kwargsを利用できる。

.agg(myfunc, 100,200) や .agg(myfunc, low=100,high=200)

◆p.160~

print([attr for attr in dir(grouped) if not attr.startswith('_')])

◆グループの数

grouped.ngroups

◆キー取得

grouped.groups.keys()

◆グループを取得

grouped.get_group(【グループラベルのタプル】)

◆ざっとオーバービューする時の定石

from IPython.display import display

from n,g in grouped
print(n)
display(g.head(3))

grouped.head(2).head(6)

grouped.nth([1,-1]).head(8) nthメソッドにより各グループの先頭と末尾の行
を取得

◆groupオブジェクトの/あるいはgroupオブジェクトを操作するにあたりに役立ち そうなメソッド

agg
apply

は定番として、

filter *
transform
pivot
np.where

あたり。

◆transformについて... ↓

ほかにもいろいろできるが、groupbyする前のDataFrameにグループ化後の集約値 を一律付与することができる。 ※groupbyする前のDataFrameと同じ行数となる。 → 私はこの手のgroupby後にapplyして得られた集約値を元のDataFrameにカラム追加するということをしばしばやっていたが、  ひょっとするとtransform一発で書けたのかもとこれを見て思った。

◆ pd.SeriesではなくあえてOrderDictを使うというスタイルもある。

◆グループをSeriesとDataFrameどちらで返すかでカタチが変わる。

◆ NumPy特にstatsモジュールは利用しがいがある。

◆ pandas cut 関数

bins = [-np.inf, 200, 500, 1000, 2000, np.inf]
cuts = pd.cut(foo['BAR'], bins=bins)
fooデータフレームのBARカラムの値を離散化

離散値などによりbin詰めしたグループ化ができる。

◆pandasではgroupby メソッドに任意のオブジェクトを渡せる (現在のDataFrameに全く関係ないものでグループ分けできる!)

diff shift


整然形式にデータを再構成

tidyデータを/tidyデータになるようにあれこれの例が載っている。 pandasの特にindexのマスターになるにはこれに良くなれておくのが良いだろう。

  • 65 変数値カラム名をstackで整然化(tidy化)
  • 66 変数値カラム名をmeltで整然化 例. りんごとオレンジとバナナの地域ごとの生産量クロス集計を整然化

コツ stack()、reset_index()、columsで代入あるいは Seriesのrename_axisメソッド を使ったのちにreset_index()

別解 meltメソッドを使う

ちなみに、水平方向のカラム名を鉛直方向のカラム値に変形することを melting、stacking、unpivoting などと呼ぶ

  • 67 複数の変数グループを同時にスタック 映画の出演者1の名前とSNSのイイねの数、~出演者3までの同項目の表を整然 データにする wide_to_long

  • 68 スタックしたデータを元に戻す unstack、pivot

  • 69 groupby集約の後でunstack クロス集計表の縦横転置

  • 70 groupby集約でpivot_tableの代用

  • 71 変形を容易にするレベル軸の名前変更 rename_axisによりカラムレベル自体に名前をつける cg.rename_axis(['AGG_COLS','AGG_FUNCS'], axis='columns') swaplevelメソッド sort_indexメソッド

  • 72 複数の変数がカラム名になっている場合の整然化

  • 73 複数の変数がカラム値の場合の整然化 MultiIndexメソッドのdroplevel squeeze

  • 74 複数の値が同じセルにある場合の整然化

  • 75 変数がカラム名とカラム値になっている場合の整然化 各地域の気圧、気温、湿度がそれぞれ各行(1地域あたり3行)に記録されている。 年度ごとのこの値が水平方向に格納されている。 水平方向の時系列。

  • 76 複数の観察が同じテーブルにある場合の整然化


pandasオブジェクトの結合 (p.233)

結合

append concat merge

.locで1行追加することもできる。
names.loc[len(names)] = {'Name':'FOO','Age':15}

◆ append ignore_indexパラメータ (appendそのものではないが) Series.to_dict() とリスト内包表記

◆ concat 個人的に意外だった使い方がいくつかあった。

s_list = [データフレーム1, データフレーム2] pd.concat(s_list) → 鉛直に連結する。 pd.concat(s_list, keys=['2016','2017'], names=['Year','Symbol']) ラベル指定とインデックスレベルの名前を変えることができる。

read_htmlでダイレクトにhtml中の表をDataFrameに取込できる match, attrsパラメータの使いこなしがキモ。 ここでも欠損値を取り扱うffill, fillnaが活躍

Pythonの辞書アンパッキング →(辞書)アンパッキングと呼ぶのね

data = (3,5,7)
san,go,nana = data

のようなやつのこと。

パラメータ名と値を含む辞書を、**をつけて関数に渡す、例えば、
func(**ABCval)
などとやるとABCvalの辞書を元に
func(a='x1',b='x2',c='x3')と指定したような扱いになる

◆ p.255 concat、join、mergeの違い 個人的には、 ①concatはインデックスに重複があればエラー 他2つは、デカルト積計算 ②3者のアラインメントの違い

というところがまとめてあったのがうれしい。

この書籍の章で学んだことは、こちら↓の記事に活きてます。

itdepends.hateblo.jp

以上

*1:※セルというのはEXCELの影響で便宜上このように呼びました