はじめに:zip(*sorted(zip(list1, list2)))が何やってるか分からなかった。
- 202203 現在、開催中の Kaggle competition「h-and-m-personalized-fashion-recommendations」に参加中。
- コンペ内の Notebook を読んでいる際に、
zip(*sorted(zip(list1, list2)))
の意味がよく分からなかった。 - 備忘録として残しておきます。
理解できなかったコード
実際に理解できなかったコードは以下。
_, popular_items = zip(*sorted(zip(popular_items_group, popular_items_group.keys()))[::-1])
'''
ここで、すでに生成済みの変数の意味合いは以下。
-------------------
popular_items_group:pd.Seriesオブジェクト。indexは各アイテムのユニークなid, valueは各アイテムの人気度合いを表す指標。
'''
「zip したものを並び替えてまた zip?」「あとアスタリスク*はなぜ?」といった感じで、よく分からなかったので内側の処理から順番に化確認してみました。
上の処理は実際に何やってる?
結論から書くと、上の処理zip(\*sorted(zip(list1, list2)))
は、「list2
をlist1
の昇順(or 降順)ソートに合わせてソートする」処理を一行で記述したもので、よく使われるようです。
一応、内側の処理から順番に、確認する事にします。
その前にまず、既に定義された変数であるpopular_items_group
が分かりづらいので、以下のように x と y に代入しておきます。
x = popular_items_group # アイテムの人気度
y = popular_items_group.keys() # アイテムid
ではまずは最初の zip()関数から。
# popular_items_groupのindexと要素をzipで結合
a = zip(x, y)
# =>List[(x, y)](タプルのリストになる。厳密にはlistじゃなくイテレータ?)
続いて sorted()関数の処理。
# [(人気度, アイテムid)]のイテレータをソートする。
# sorted()はタプルのイテレータに対しては、デフォルトでは最初の要素xをkeyとしてソートする。
b = sorted(zip(x, y))
# =>[(人気度, アイテムid)]を、人気度の昇順でソートしたリスト
実際には、ソートしたリストに対してスライス表記[::-1]
でマイナスステップを用いて、昇順から降順に逆転させていますね。
c = b[::-1]
# =>[(人気度, アイテムid)]を、人気度の降順でソートしたリスト
# [::1]の場合はステップ数=1なので、[::]や[:]と同じ。[::-1]だとマイナスステップ
最後に二回目(外側)の zip()関数です。
d, e = list(zip(*c))
print(e)
('0909370001', '0924243001', '0918522001', '0865799006', ...)
我々が手にしたい情報は、「list2
を、list1
の昇順(or 降順)ソートに合わせてソートする」処理を施したlist2
(上のコードにおけるe
)です。
なので*
アスタリスクを記述する事で、タプルのリスト[(人気度, アイテム id)]を unpacking しています。
unpacking ってなんぞやって事ですが、この場合は**「"要素数 2 のタプル"のリスト」を展開して「2 つのリスト」に代入する処理**、みたいです。
ちなみに unpacking しないと、「'要素数 2 のタプル'が中に格納された'要素数 1 のタプル'のリスト」(2)のようになってしまいます。
print(list(zip(c)))
[((332.8648934398934, '0909370001'),), ((314.63786213786216, '0924243001'),),...]