Python でネストされたリストをフラット=一次元のリストにする方法

Python でネストされたリストをフラット=一次元のリストにする方法

** Sorry, this note is Japanese only, but please take a look at some code snippets. Hope it helps you a bit!

前回 機械学習の際のデータ処理の一環として、カテゴリとその頻度が含まれているデータを、各データで1レコード・カテゴリごとに頻度行分だけ、というテーブルに変換する方法について調べていたんだけど、その際にネストされたリストをフラットに(つまり、一次元のリストに)する必要があった。
結局その時は functools.reduce を2回実行したんだけど、一般的にネストされたリストって何階層にネストされてるかわかんないので、何階層にネストされててもフラットにできる方法を考えてみた。

そもそもの問題設定 ~ pandas の DataFrame とやろうとしてること

今、データが何らかの理由で以下のような形をしているとする。

ID Category Frequency
0 A 1
1 B 3
2 C 1
3 D 1
4 E 2

これを、このように変換したい、というのが前回の問題設定だった。

ID Category
0 A
1 B
2 B
3 B
4 C
5 D
6 E
7 E

※ 詳しくは前回記事を見てください
datalove.hatenadiary.jp
んで、その前回の方法の中で、functools.reduce を使って、次のような処理をしているところがある。

mylist1 = df[['category', 'frequency']].values  # mylist1 は numpy.ndarray  
[reduce(lambda x,y: [x]*y, l) for l in mylist1]  

この2行めの実行結果は、

[['A'], ['B', 'B', 'B'], ['C'], ['D'], ['E', 'E']]  

というような、df[‘category’] を df[‘frequency’] の数だけ繰り返した、ネストされたリストになります。
このリストをフラットにするために、functools.reduce をもっかい使って、

reduce(lambda x,y: x+y, [reduce(lambda x,y: [x]*y, l) for l in mylist1])  

のようにする、というのが前回やってたことでした。
※ x+y の x と y にネストされたリストの中身が順番に入っていくので、結果的に一次元のリストになる。

・・・でも、一般的にネストされたリストって、どうやってフラットにするんだろう・・・?
まさか reduce( … , [reduce …, [reduce …, ]]]) みたいに、reduce を重ねるわけないよね・・・?
※ ここからは、前回の問題の趣旨からは外れます

というところからが、今日のお題です。

ネストされたリストをフラット=一次元のリストにする 解決方法

いろいろ調べた結果、Iterable とメソッドの再帰呼び出しを使うみたいです。

gist.github.com

flatten の中で、引数に設定された nested_list をもっかい flatten に再帰的に渡すところがミソ。
ただ、実行速度やメモリの消費量など効率の点では、再帰よりもフツーの繰り返しの方がいいらしいので。データのサイズが大きい時は注意が必要かもしれません。

その他 データ分析 ・機械学習 関係の記事もどうぞ

datalove.hatenadiary.jp
datalove.hatenadiary.jp
datalove.hatenadiary.jp
datalove.hatenadiary.jp
datalove.hatenadiary.jp
datalove.hatenadiary.jp