sklearn.manifold.tsneのメモリリークを回避するために(Anacondaのみ)
現象
大規模データでscikit-learnのmanifold.tsneを使うとメモリエラーを起こします。Pythonでメモリエラーか。
原因
mklのバグ、、、らしい。以前にscikit-learnにイシューが立っていたようだ。バージョンが上がった現在でも改善はされていない。このイシューはPython2系時点だった。今回はPython3系なのでやはりバージョンも関係ない。
Python crashes when calculating large t-SNE · Issue #4619 · scikit-learn/scikit-learn · GitHub
対策(翻訳)
Anacondaのみだが
conda install nomkl
これで解決できる。これでintel-mkl ライブラリを使わないためメモリリークを起こさないようだ。
非Anacondaの場合はラッパーを利用することになる。
GitHub - danielfrg/tsne: A python wrapper for Barnes-Hut tsne
自分はAnacondaだったのでこっちは試していない。念の為。
pandasで要素内に特定の文字列が含まれる行を抜き出したい
列Aに"美"が含まれる行を抜き出す
index | A | ... |
---|---|---|
0 | 太郎 | ... |
1 | 真由美 | ... |
2 | 和則 | ... |
3 | 和美 | ... |
4 | 哲也 | ... |
5 | 司 | ... |
というDataFrame(df)があったとする。 このとき、"美"という文字列を含む行だけ欲しいという場合にどうするか。
str.containsを使う
df[df["A"].str.contains("美")]
これで
index | A | ... |
---|---|---|
1 | 真由美 | ... |
3 | 和美 | ... |
が返ってくる。 詳細はドキュメントで確認して欲しい。
pandasで条件にあった値を持つ行を削除する場合
列Aにあるnという値を持つ行を削除したい
df | A | B | C |
---|---|---|---|
0 | k | n | n |
1 | n | n | n |
2 | n | k | k |
... | ... | ... | ... |
1000 | n | m | m |
... | ... | ... | ... |
この1行目2行目に該当する行を削除したい時にどうするか。
もちろんこの簡単な例ではdf.drop([1,2,1000])
でいける?
まさかそんな話ではない。
方針
- Aにnという値を持つ行を削除する
- Aにn以外の値を持つ行を抽出する
方針1
正直わからんかった。df.drop()
はindexの値をリストとして与えればうまく削除できる。
ただ, df[df.A == n]
で得られたDataFrameからindexのリストを取得することはどこを見ても書いてなかったしそもそもできないのかもしれない。
過去にindexの値を取得するスクリプトを書いた気がするがそれはまた別の機会に。
方針2
df[df.A != n]
これでよい。削除する削除するという頭だとどうしてもdf[df.A == n]
をdropすることばかりに頭がいくが, 逆に考えてn以外の値を持つ行を抽出する。そう考える。
matplotlib savefigをサーバーで行う場合
そのままサーバーでも画像出力させようとすると
Traceback ... ... RuntimeError: Invalid DISPLAY variable
うまくいかない
解決策
import matplotlib as mpl mpl.use('Agg')
これを追加する。見つかるドキュメントにはそれしか書いておらず「追加したのにうまくいかない」状況が起こりうる。
注意点
- 追加するのは,
import matplotlib.pyplot as plt
の前でなければならない - 追記するファイルは, savefigがあるファイルという訳ではなく, 実行するファイルである
これに気をつければ問題なく画像出力ができるはずである. PNGの他の場合も知りたいなんてときは以下に詳しくまとまっている,
matplotlibでOverflowError: In draw_path: Exceeded cell block limitというエラーが出る
引っかかったところ
matploblibで比較的大きなデータをプロットしようとしたとき, plt.savefig
をしようとして
OverflowError: In draw_path: Exceeded cell block limit
というエラーが出た.
解決策
結構簡単で,
import matplotlib as mpl mpl.rcParams['agg.path.chunksize'] = 100000
この文を加えるだけ. 100000という数字は大きければとりあえずOKなようだ.
numpy savetxtで複素数も扱うとき
savetxtを複素数でも扱う
普通savetxtは実数だけで扱っているので複素数のことなど気にも留めない。 そのまま複素数もいけるのかと思いきや、そうは問屋は卸さない。
問題
複素数を含む数をarrayに入れたまま保存すると、(1.00000000e + 1,0000000ej)なんて形になってしまう。この括弧が厄介でこれのせいでpandasでも呼び出せはするがアクセスができないなんてことになる。
解決
numpy savetxt complexとググれば答えは見つかりはする。
python - Writing and reading complex numbers using numpy.savetxt and numpy.loadtxt - Stack Overflow
ここでは
numpy.savetxt(save, array.reshape(1, array.shape[0]), newline = "\r\n", fmt = '%.4f%+.4fj '*4)
こうやるといい、と書いてある。しかしこのまま保存するとcsvにならず連続で4つの実数と虚数の組が並んでしまう。delimiterをホワイトスペースかカンマにするだけなのだが、お好きな方で。 カンマにするときは、
numpy.savetxt(savefilename, array, fmt = '%.4f%+.4fj, '*4, delimiter=',')
とすると綺麗にCSVになってくれる。 *4
は、要するに列数だ。100列あるなら*100
になるというわけ。また肝はfmt = '%.4f%+.4fj, '*4,
でfmtの中にカンマを指定すれば思い通りに出力してくれる。
こんな感じでいじることができるので、任意の出力に対応することができる、らしい。複素数は今回のように出力するのが良いのではないだろうか。
Pythonで並列処理入門
入門編でやれること
リストを順に処理するときに並列で処理したい!
data_list = ["a", "b", "c", "d"] for i in data_list: #Do something
こういうのをコア数に応じて並列で処理してさくっと終えたい。ときに使える。
どうやるか
from multiprocessing import Pool data_list = ["a", "b", "c", "d"] def wrapper_main(nakami): #Do something myprocess = Pool() myprocess.map(wrapper_main, data_list) myprocess.close()
実際に書く量はほとんど変わらない。もちろん、ひとつのリストの中身だけで完結することが大前提(並列処理って言ってるしね)。
少しずつ見ていきたい。
from multiprocessing import Pool
これで呼び出し
def wrapper_main(nakami): #Do something
本来やりたい処理をここに入れる。変数nakamiはdata_listの中身のこと。ラッパーを書くときは、リストを引数に与えるのではなくリストの中身を与えた場合の処理を書く。
myprocess = Pool()
myprocess.map(wrapper_main, data_list)
myprocess.close()
これはほとんどおまじない。Poolの中に例えばPool(12)とすると12コアだけ使ってくれる。何も入れないとフルで使うことになる。 肝心なのはプロセスオブジェクト.map(関数名, リスト)という使い方。
これさえ守ればあっという間にマルチプロセスができる。
コアごとに違う処理を押し付けたい場合やwrapperの引数が二次元リストだったり複数あったりする場合は中級編として既存のブログ等を参考にすればできる。マルチスレッドとマルチプロセスの違いなども割愛。