pandas 0.16.0/0.16.1 の主要な新機能
先日 5/11 に pandas 0.16.1 がリリースされた。前バージョンである 0.16.0 とあわせて、主要な変更点である以下3点の概要をまとめたい。各見出しの括弧内には対応したバージョンを記載した。
- 簡単な列追加 /
DataFrame.assign
(0.16.0) - 文字列処理の強化 (0.16.0/0.16.1)
- ランダムサンプリング
DataFrame.sample
(0.16.1)
変更点全体はリリースノートを参照。上記3点以外にも便利な変更はあるのだが、 Categorical や Frequency など 元機能の説明がないとわからない箇所なので別途、、。
簡単な列追加 / DataFrame.assign
(0.16.0)
DataFrame
への列追加をより簡潔に行うためのメソッドとして、DataFrame.assign
が追加された。R {dplyr}
の mutate
関数に似た書式で複数列の追加ができる。
これまで列追加の際には カラムを指定して代入し、元データを破壊的に変更する必要があった。
import pandas as pd df = pd.DataFrame({'A':[1, 2, 3], 'B':[4, 5, 6]}) df # A B # 0 1 4 # 1 2 5 # 2 3 6 # これまでの列追加 df['C'] = [7, 8, 9] df # A B C # 0 1 4 7 # 1 2 5 8 # 2 3 6 9
assign
を使うと、作成したい列名をキーワード引数として以下のように書ける。また、戻り値は元データに列追加したコピーとなり、元データ自体は変更されない。
# D列, E列を追加 df.assign(D=[10, 11, 12], E=[13, 14, 15]) # A B C D E # 0 1 4 7 10 13 # 1 2 5 8 11 14 # 2 3 6 9 12 15 # 元データはそのまま df # A B C # 0 1 4 7 # 1 2 5 8 # 2 3 6 9
キーワード引数の値には通常の列作成時と同じ型が渡せる。各列の値を組み合わせた列 + ダミー列を同時に作りたければ、
df.assign(AB=df['A'] * df['B'], AC=df['A'] + df['C'], dummy=1) # A B C AB AC dummy # 0 1 4 7 4 8 1 # 1 2 5 8 10 10 1 # 2 3 6 9 18 12 1
キーワード引数として渡せない列名、例えば記号や日本語を含む列名は、一度 辞書にしてから渡せばよい。
keys = {'A*B': df['A'] * df['B'], 'A+B':df['A'] + df['B']} df.assign(**keys) # A B A*B A+B # 0 1 4 4 5 # 1 2 5 10 7 # 2 3 6 18 9
補足: メソッド自体は 0.16.0 で追加され、0.16.1 でキーワード引数の処理順序がアルファベット順に固定された。
文字列処理の強化 (0.16.0/0.16.1)
pandas
での文字列処理について過去に以下の記事を書いたことがあるのだが、当時はアクセサから利用できるメソッドが限定されていて、少し手間がかかるところがあった。
0.16.0, 0.16.1 で、.str
アクセサに以下のメソッド群が追加された。それぞれ、 Python 標準の文字列メソッドと同一の処理を Series
内の値に対して適用するもの。
Methods | ||||
---|---|---|---|---|
isalnum |
isalpha |
isdigit |
isspace |
islower |
isupper |
istitle |
isnumeric |
isdecimal |
find |
rfind |
ljust |
rjust |
zfill |
capitalize |
swapcase |
normalize |
partition |
rpartition |
index |
rindex |
translate |
補足 str.normalize
は ユニコード正規化 ( unicodedata.normalize
) を値に対して適用するもの。
補足 .str
アクセサから利用可能なメソッド全体はこちら。
df = pd.DataFrame({'A': ['xxx', '3', 'yyy'], 'B': [1, 2, 3]}) df # A B # 0 xxx 1 # 1 3 2 # 2 yyy 3 # 先頭を大文字に df['A'].str.capitalize() # 0 Xxx # 1 3 # 2 Yyy # Name: A, dtype: object # 文字列が数値がどうかを調べる df['A'].str.isdigit() # 0 False # 1 True # 2 False # Name: A, dtype: bool # 5桁分を 0 パディング df['A'].str.zfill(5) # 0 00xxx # 1 00003 # 2 00yyy # Name: A, dtype: object
やりたいことに応じて適当に組み合わせると、かなり柔軟な処理がかける。例えば 数値の文字列のみを 0 パディングしたければ、
df.loc[df['A'].str.isdigit(), 'A'] = df['A'].str.zfill(5) df # A B # 0 xxx 1 # 1 00003 2 # 2 yyy 3
補足 DataFrame.loc
の意味はこちらの記事参照。
また、0.16.1 から .str
アクセサを Index
からも呼び出せるようになった。これまでは 列名/行名に対する文字列処理は .map
を使って関数適用する必要があったが、.str
を使えば以下のように書ける。
df # A B # 0 xxx 1 # 1 00003 2 # 2 yyy 3 df.columns.str.lower() # Index([u'a', u'b'], dtype='object') # 列名を小文字に変更 df.columns = df.columns.str.lower() df # a b # 0 xxx 1 # 1 00003 2 # 2 yyy 3
str.split
のように複数の値を返しうる処理については、expand
オプションを利用して 返り値の型を制御できる。互換性維持のため、既定値はメソッドにより異なる。APIドキュメントを参照。
expand=False
: 返り値の次元を増やさない = 返り値はSeries
もしくはIndex
expand=True
: 返り値の次元を増やす = 返り値はDataFrame
もしくはMultiIndex
補足 これまで同様の制御をおこなっていた return_type
オプションは deprecate されており、将来のバージョンで削除される。
s = pd.Series(['a,b', 'a,c', 'b,c']) # 返り値は Series s.str.split(',') # 0 [a, b] # 1 [a, c] # 2 [b, c] # dtype: object # 返り値は DataFrame s.str.split(',', expand=True) # 0 1 # 0 a b # 1 a c # 2 b c idx = pd.Index(['a,b', 'a,c', 'b,c']) # 返り値は 1 レベルの Index idx.str.split(',') # Index([[u'a', u'b'], [u'a', u'c'], [u'b', u'c']], dtype='object') # 返り値は 2 レベルの MultiIndex idx.str.split(',', expand=True) # MultiIndex(levels=[[u'a', u'b'], [u'b', u'c']], # labels=[[0, 0, 1], [0, 1, 1]])
ランダムサンプリング DataFrame.sample
(0.16.1)
Series
, DataFrame
, Panel
から適当なデータをサンプリングするためのメソッドとして、.sample
が追加された。
ここでは DataFrame.sample
を例としてその処理を記載する。まず以下のようなデータを用意した。
df = pd.DataFrame({'A': [1, 2 ,3, 4, 5], 'B': ['a', 'b', 'c', 'd', 'e']}) df # A B # 0 1 a # 1 2 b # 2 3 c # 3 4 d # 4 5 e
DataFrame.sample
は 既定では 1 行をランダムにサンプリングする。
n
: サンプルサイズを指定する。既定は 1。axis
: サンプリングするレコードの方向を指定する。0
(既定) で行のサンプリング、1
で列のサンプリング。
# 1 行の抽出 df.sample() # A B # 3 4 d # 3 行の抽出 df.sample(3) # A B # 0 1 a # 4 5 e # 2 3 c # 1 列の抽出 df.sample(axis=1) # A # 0 1 # 1 2 # 2 3 # 3 4 # 4 5
また、サンプルサイズでなく抽出比を指定する場合は frac
を指定する。
df.sample(frac=0.4) # A B # 3 4 d # 1 2 b
最後に、replace
オプションを利用して 抽出方法を変更することができる。
replace=False
(既定): 非復元抽出。サンプリングされた各要素の重複を許さない。replace=True
: 復元抽出。各要素の重複を許す。
# 復元抽出。2行目、4行目が重複 df.sample(n=4, replace=True) # A B # 1 2 b # 2 3 c # 0 1 a # 2 3 c # 非復元抽出では 元のデータ数以上のサンプルサイズは取れない df.sample(n=6) # ValueError: Cannot take a larger sample than population when 'replace=False' df.sample(n=6, replace=True) # A B # 1 2 b # 4 5 e # 0 1 a # 1 2 b # 2 3 c # 4 5 e
補足 これまでは index の要素をサンプリングして選択する必要があった。以下の記事参照。
まとめ
0.16.0 / 0.16.1 の変更点のうち、以下 3 点の概要をまとめた。
- 簡単な列追加 /
DataFrame.assign
(0.16.0) - 文字列処理の強化 (0.16.0/0.16.1)
- ランダムサンプリング
DataFrame.sample
(0.16.1)
他にも、バグ修正 / 挙動・仕様の統一など 様々な改善が入っているので使ってみてください。
Pythonによるデータ分析入門 ―NumPy、pandasを使ったデータ処理
- 作者: Wes McKinney,小林儀匡,鈴木宏尚,瀬戸山雅人,滝口開資,野上大介
- 出版社/メーカー: オライリージャパン
- 発売日: 2013/12/26
- メディア: 大型本
- この商品を含むブログ (9件) を見る