今回は、複数カラムの特徴量を一度に作りたいなーっていう、たまに思うやつを書く。
結論から先に書いてしまうと、返り値を Series
にしてやれば良い。
使った環境は次の通り。
$ sw_vers ProductName: Mac OS X ProductVersion: 10.14.3 BuildVersion: 18D109 $ python -V Python 3.7.2 $ pip list | grep pandas pandas 0.24.2
下準備
まずは下準備として pandas をインストールしておく。
$ pip installp pandas
サンプルデータとしてくだものの名前が入った DataFrame
を用意する。
>>> import pandas as pd >>> data = [ ... ('Apple'), ... ('Banana'), ... ('Cherry'), ... ] >>> df = pd.DataFrame(data, columns=['name'])
複数カラムの特徴量を作る
例えば n-gram の特徴量をくだものの名前から抽出することを考える。
そのために、次のような n-gram を計算して配列として返す関数を定義する。
>>> def n_gram(x, n=1): ... return [x[i : i + n] for i in range(len(x) - n + 1)] ...
これを先ほどの DataFrame
の name
カラムに適用すると、次のようになる。
>>> df.name.apply(n_gram) 0 [A, p, p, l, e] 1 [B, a, n, a, n, a] 2 [C, h, e, r, r, y] Name: name, dtype: object
ちゃんと unigram が計算できている。
bigram を計算したいときは、次のように引数に 2
を指定すれば良い。
>>> df.name.apply(n_gram, args=(2,)) 0 [Ap, pp, pl, le] 1 [Ba, an, na, an, na] 2 [Ch, he, er, rr, ry] Name: name, dtype: object
でもこれ、めんどくさいから一度に計算したくない?ってなる。
なったときは、次のように各 n-gram を計算して Series
として返すラッパーを書いてやる。
>>> def multiple_n_gram(x, n_max=3): ... return pd.Series([n_gram(x, n=i) ... for i in range(1, n_max + 1)]) ...
上記のデフォルトでは trigram まで計算する。
これを、先ほどと同じように適用してみる。 すると、三次元の特徴量が一度に抽出できた。
>>> df.name.apply(multiple_n_gram) 0 1 2 0 [A, p, p, l, e] [Ap, pp, pl, le] [App, ppl, ple] 1 [B, a, n, a, n, a] [Ba, an, na, an, na] [Ban, ana, nan, ana] 2 [C, h, e, r, r, y] [Ch, he, er, rr, ry] [Che, her, err, rry]
次のようにカラム名のリストを渡すと、既存の DataFrame
に名前をつけながら一度に挿入できる。
>>> df[['unigram', 'bigram', 'trigram']] = df.name.apply(multiple_n_gram) >>> df name unigram bigram trigram 0 Apple [A, p, p, l, e] [Ap, pp, pl, le] [App, ppl, ple] 1 Banana [B, a, n, a, n, a] [Ba, an, na, an, na] [Ban, ana, nan, ana] 2 Cherry [C, h, e, r, r, y] [Ch, he, er, rr, ry] [Che, her, err, rry]
もちろん、ふつうに pandas.concat()
しても良い。
n-gram の返り値を Series にしてみる
先ほどは各 n-gram を異なるカラムにしただけで、その中の処理が返す値は単なるリストだった。
続いては、試しに n-gram の処理自体が返す値を Series
にしてみよう。
>>> def n_gram_series(x, n=1): ... return pd.Series(x[i : i + n] for i in range(len(x) - n + 1)) ...
くだものの名前は固定長ではないので、返す Series
の長さもまちまちになる。
どうなるだろうか。
先ほどと同じように name
カラムに適用してみる。
>>> df.name.apply(n_gram_series) 0 1 2 3 4 5 0 A p p l e NaN 1 B a n a n a 2 C h e r r y
上記から、返すカラムの長さがまちまちなときは、足りない部分に NaN
が補完されることがわかる。
いじょう。
スマートPythonプログラミング: Pythonのより良い書き方を学ぶ
- 作者: もみじあめ
- 発売日: 2016/03/12
- メディア: Kindle版
- この商品を含むブログ (1件) を見る