リストのソート
前回、Jupyter Notebookで音を鳴らしたり、保存する方法を解説しました。
今回は複数のリスト(配列)において、要素の順番を同時にソート(並び替え)する方法を紹介します。
例えばこんな2つのリストがあったとします。
num_list = [5, 3, 4, 1, 2]
str_list = ['a', 'c', 'b', 'e', 'd']
そしてnum_listとstr_listの同じインデックスの要素は関連しているとします。
つまりnum_listの「5」とstr_listの「’a’」はつながりがあるということです。
そのためこれらの関連を崩さずにソート(並び替え)をしたというとき、どうしたらいいかというのが今回のお話です。
それでは始めていきましょう。
1.zip関数を使う方法
基本的な方法がzip関数を使う方法だと思います。
zip関数はfor文と合わせて使うことが多いですが、複数のリストやタプルをまとめて処理をする際に使われる関数です。
今回の場合は以下のような流れで処理をしていきます。
- 複数のリストをzip関数でまとめる
- ソートする
- zip関数を解除する
ということで試してみましょう。
num_list = [5, 3, 4, 1, 2]
str_list = ['a', 'c', 'b', 'e', 'd']
zipped_lists = zip(num_list, str_list)
zipped_sorted_lists = sorted(zipped_lists)
sorted_num_list, sorted_str_list = zip(*zipped_sorted_lists)
print(sorted_num_list)
print(sorted_str_list)
(1, 2, 3, 4, 5)
('e', 'd', 'c', 'b', 'a')
「zip(num_list, str_list)」で二つのリスト(num_list、str_list)をまとめます。
この際、ソートしたいリストを一番最初の引数に配置します(今回の場合はnum_list)。
そして「sorted(zipped_lists)」でソートします。
「zip(*zipped_sorted_lists)」でzipを解除します。
zip化されたリストの解除は「zip(*zip化されたリスト)」で解除できます。
この際zip化したときにまとめた分のリストが出てきますので注意してください。
これにより元々は「5, 4, 3, 2, 1」、そして[‘a’, ‘c’, ‘b’, ‘e’, ‘d’]という並びだったnum_listとstr_listが(1, 2, 3, 4, 5)、(‘e’, ‘d’, ‘c’, ‘b’, ‘a’)というタプルになりました。
もしリストにしたい場合は「list(リスト化したいタプル)」でリストに変換してください。
先ほど「ソートしたいリストを一番最初の引数に配置」とお話ししましたが、この順番を変えてstr_listを最初の引数にするとこうなります。
num_list = [5, 3, 4, 1, 2]
str_list = ['a', 'c', 'b', 'e', 'd']
zipped_lists = zip(str_list, num_list)
zipped_sorted_lists = sorted(zipped_lists)
sorted_num_list, sorted_str_list = zip(*zipped_sorted_lists)
print(sorted_num_list)
print(sorted_str_list)
実行結果
('a', 'b', 'c', 'd', 'e')
(5, 4, 3, 2, 1)
また「sorted(ソートしたいリスト)」でのソートはデフォルトでは昇順になっています。
もし降順にしたい場合はオプションに「reverse=True」を追加します。
num_list = [5, 3, 4, 1, 2]
str_list = ['a', 'c', 'b', 'e', 'd']
zipped_lists = zip(num_list, str_list)
zipped_sorted_lists = sorted(zipped_lists, reverse=True)
sorted_num_list, sorted_str_list = zip(*zipped_sorted_lists)
print(sorted_num_list)
print(sorted_str_list)
実行結果
(5, 4, 3, 2, 1)
('a', 'b', 'c', 'd', 'e')
2.Pandasを使う方法
もう一つはPandasを使う方法です。
Pandasの場合は列や行での要素はそれぞれ関連した要素となっており、簡単にソートできるようになっています。
とういうことでリストをまずはPandasのデータフレームに変換します。
import pandas as pd
num_list = [5, 3, 4, 1, 2]
str_list = ['a', 'c', 'b', 'e', 'd']
df = pd.DataFrame([num_list, str_list], index=['num_list', 'str_list'])
print(df)
df = df.transpose()
print(df)
実行結果
0 1 2 3 4
num_list 5 3 4 1 2
str_list a c b e d
num_list str_list
0 5 a
1 3 c
2 4 b
3 1 e
4 2 d
とりあえずリストからデータフレームに変更してみたら行と列が逆になっていたので、「.transpose()」で行と列を入れ替えています。
そしてPandasで値をソートするには「df.sort_values(ソートする列名)」です。
また最後にリストに戻すには「df[列名].tolist()」ですので、こうなります。
import pandas as pd
num_list = [5, 3, 4, 1, 2]
str_list = ['a', 'c', 'b', 'e', 'd']
df = pd.DataFrame([num_list, str_list], index=['num_list', 'str_list'])
df = df.transpose()
df_sorted = df.sort_values('num_list')
print(df_sorted['num_list'].tolist())
print(df_sorted['str_list'].tolist())
実行結果
[1, 2, 3, 4, 5]
['e', 'd', 'c', 'b', 'a']
確かにソートすることができました。
「sort_values()」のデフォルトは昇順ですが、降順にするには「ascending=False」を追加します。
import pandas as pd
num_list = [5, 3, 4, 1, 2]
str_list = ['a', 'c', 'b', 'e', 'd']
df = pd.DataFrame([num_list, str_list], index=['num_list', 'str_list'])
df = df.transpose()
df_sorted = df.sort_values('num_list', ascending=False)
print(df_sorted['num_list'].tolist())
print(df_sorted['str_list'].tolist())
実行結果
[5, 4, 3, 2, 1]
['a', 'b', 'c', 'd', 'e']
処理速度の比較
せっかくなので「%%timeit」を使って、上記2種の処理速度を計測してみましょう。
%%timeit
num_list = [5, 3, 4, 1, 2]
str_list = ['a', 'c', 'b', 'e', 'd']
zipped_lists = zip(num_list, str_list)
zipped_sorted_lists = sorted(zipped_lists)
sorted_num_list, sorted_str_list = zip(*zipped_sorted_lists)
実行結果
1.18 µs ± 20.6 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)
%%timeit
import pandas as pd
num_list = [5, 3, 4, 1, 2]
str_list = ['a', 'c', 'b', 'e', 'd']
df = pd.DataFrame([num_list, str_list], index=['num_list', 'str_list'])
df = df.transpose()
df_sorted = df.sort_values('num_list')
実行結果
612 µs ± 28.7 µs per loop (mean ± std. dev. of 7 runs, 1,000 loops each)
ご覧の通り、圧倒的にzip関数の方が速かったです。
素直にzip関数を使いましょう。
次回はWebカメラを使って動画を撮影する方法を紹介します。
ではでは今回はこんな感じで。
コメント