今回は実際にコードを使用しながらPythonの基本を解説します。最後まで進めばマッチングアプリ的なコードが完成します。
Pythonの基礎が理解できると、次のステップは実際にコードを使いながら勉強するのが一番です。今回はマッチングアプリ的なPythonコードを考えてみましたので、実際に皆さんの友達にあてはめながら進めてもらえればいいかなと思います。
前提条件
今回はある大学サークルの10名を仮定して、それぞれの友人関係や趣味から友達マッチング(男女関係なくです)を進めてみるコードを考えました。
前提としてサークル部員は男性5名、女性5名です。
まずは、部員の名前とIDを含む変数を作成します。
students = []
names = ["しょうた", "つとむ", "けんた", "ゆうた", "とおる", "まな", "あや", "みほ", "さおり", "あさみ"]
for i in range(len(names)):
student = {"id": i, "name": names[i]}
students.append(student)
- for文は、各部員に対して、辞書(dictionary)を作成します。辞書はキーと値のペアを持っており、ここでは "id" と "name" がそれぞれのキーです。
- このコードでは、
names
リスト内の各名前に対して、その名前と対応するIDを持つ部員の辞書を作成し、それをstudents
リストに追加しています。これにより、students
リストには各部員の情報が辞書形式で格納されます。例えば、students[0]
は{"id": 0, "name": "しょうた"}となります。
辞書を出力すると、
students
[{'id': 0, 'name': 'しょうた'},
{'id': 1, 'name': 'つとむ'},
{'id': 2, 'name': 'けんた'},
{'id': 3, 'name': 'ゆうた'},
{'id': 4, 'name': 'とおる'},
{'id': 5, 'name': 'まな'},
{'id': 6, 'name': 'あや'},
{'id': 7, 'name': 'みほ'},
{'id': 8, 'name': 'さおり'},
{'id': 9, 'name': 'あさみ'}]
このようにIDと名前が含まれた辞書ができました。
友達関係を整理
次にサークル内の友達関係を調べてみたところ、サークル内の友人関係をが分かったので、データに入力します。
friends = [
(0, 1),(0, 2),
(1, 0),(1, 3),
(2, 0),(2, 3), (2, 5), (2, 7),
(3, 1), (3, 2), (3, 4),(3, 5),
(4, 3), (4, 5),
(5, 2), (5, 3), (5, 4),(5, 6),(5, 7),
(5, 8),(6, 5),(6, 7),(6, 8),
(7, 2),(7, 5),(7, 6),
(8, 5),(8, 6),(8, 9),
(9, 5), (9, 8)
]
上のリストをもう少し分かりやすいように、各部員に対して誰が友達なのかを出力します。
friends_lists = {student["id"]: [] for student in students}
existed_pairs = set() # 重複を防ぐためのセット
for i, j in friends:
if (i, j) not in existed_pairs and (j, i) not in existed_pairs:
friends_lists[i].append(j)
friends_lists[j].append(i)
existed_pairs.add((i, j)) # セットに追加して重複を防ぐ
friends_lists
- このコードでは、各部員のIDをキーにして、友達のIDを値にもつ辞書
friends_lists
を作成しています。 - その後、友達関係を表すリスト
friends
から友達のペアを取り出して、重複を防ぎながら各部員の友達リストを更新しています。最終的に、各部員の友達関係を表す辞書friends_lists
を表示します。 - リストに要素を追加する場合は、appendを使用し、セットに要素を追加する場合は、addを使います。
実行すると以下の様な部員id別の友達idが出力されます
{0: [1, 2],
1: [0, 3],
2: [0, 3, 5, 7],
3: [1, 2, 4, 5],
4: [3, 5],
5: [2, 3, 4, 6, 7, 8, 9],
6: [5, 7, 8],
7: [2, 5, 6],
8: [5, 6, 9],
9: [8, 5]}
友達の友達を見つける
では、友達関係を把握したところで、サークル部員がもっと仲良くなれるようにするためのきっかけとして、「友達の友達は仲良くなりやすい」のではという仮説から各部員の「友達の友達」を見つけることにします。
def fofs(student):
student_id = student["id"]
fof_ids_set = set(
fof_id
for friend_id in friends_lists[student_id]
for fof_id in friends_lists[friend_id]
if fof_id != student_id
and fof_id not in friends_lists[student_id]
)
return fof_ids_set
fof_lists = []
for student in students:
fof_ids_sets = fofs(student)
print(f"{student['name']}の友達の友達: {fof_ids_sets}")
fof_lists.append(fof_ids_sets)
- このコードは、あるサークル部員の友達の友達を見つける関数を使って、すべての部員に対してその情報を収集しています。
fofs
関数は、与えられた部員の友達の友達のIDを返す関数です。- 引数として
student
が渡され、ある部員のIDを取得します。 - 先に作った
friends_lists
を使用して、その部員と友達の関係を取得します。 - リスト内包表記を使用して、取得した部員の友達の友達IDを抽出し、重複を避けるためにセット(
fof_ids_set
)に格納します。 - 次に
fof_lists
という空のリストを作成します。ここには各部員の友達の友達IDセットが格納されます。 - 先に作った
students
リスト内の各部員に対して、fofs
関数を呼び出して友達の友達のIDセットを取得し、表示します。 - 最後に、それぞれの部員に対する友達の友達のIDセットを
fof_lists
に追加します。
このコードを実行すると、
しょうたの友達の友達: {3, 5, 7}
つとむの友達の友達: {2, 4, 5}
けんたの友達の友達: {1, 4, 6, 8, 9}
ゆうたの友達の友達: {0, 6, 7, 8, 9}
とおるの友達の友達: {1, 2, 6, 7, 8, 9}
まなの友達の友達: {0, 1}
あやの友達の友達: {9, 2, 3, 4}
みほの友達の友達: {0, 3, 4, 8, 9}
さおりの友達の友達: {2, 3, 4, 7}
あさみの友達の友達: {2, 3, 4, 6, 7}
という風に、友達の友達idが出力されました。
また、後で使用するために、fof_listsリストを作ったので、こちらも出力してみると、
fof_lists
[{3, 5, 7},
{2, 4, 5},
{1, 4, 6, 8, 9},
{0, 6, 7, 8, 9},
{1, 2, 6, 7, 8, 9},
{0, 1},
{2, 3, 4, 9},
{0, 3, 4, 8, 9},
{2, 3, 4, 7},
{2, 3, 4, 6, 7}]
上の様に、友達の友達idのみが入ったリストができました。
趣味も考慮してみる
「友達の友達は仲良くなりやすい」という仮説だけでは弱いと考え、さらに「友達の友達で、共通の趣味を持っている同士」なら更に交流がスムーズに深まるのでは…、という仮説に立って、追加でサークル部員の趣味について調査してみたところ、
hobbies = [
(0, "映画"), (0, "読書"), (0, "ジョギング"), (0, "パソコン"),
(1, "ジョギング"), (1, "音楽鑑賞"), (1, "料理"),
(2, "映画"), (2, "読書"), (2, "パソコン"), (2, "キャンプ"),
(3, "映画"), (3, "猫"),
(4, "映画"), (4, "パソコン"),
(5, "音楽鑑賞"), (5, "パソコン"),
(6, "読書"), (6, "キャンプ"), (6, "猫"),
(7, "映画"), (7, "旅行"), (7, "猫"),
(8, "音楽鑑賞"), (8, "ジョギング"),
(9, "ジョギング"), (9, "旅行")
]
上記のような趣味を聞き取ることができました。
このデータを「各趣味ごとにサークル部員」をまとめることにしてみます。
student_ids_by_hobbies = {}
for student_id, hobby in hobbies:
if hobby not in student_ids_by_hobbies:
student_ids_by_hobbies[hobby] = []
student_ids_by_hobbies[hobby].append(student_id)
このコードは、各趣味ごとに部員のIDをグループ化しています。
student_ids_by_hobbies
という空の辞書を作成します。この辞書は、各趣味に対して部員のIDを格納するために使用されます。for student_id, hobby in hobby
のfor文から、hobbies
の各要素から部員のIDと趣味を取り出します。if sport not in student_ids_by_hobbies
の条件文で、現在の趣味が既に辞書に存在しているかを確認します。もし存在していなければ、その趣味をキーを辞書に追加します。student_ids_by_hobbies[hobby].append(student_id)
では、対応する趣味に対応するリストに部員のIDを追加します。
このコードの結果として、student_ids_by_hobbies
には各趣味ごとに部員のIDがグループ化されて格納されることになります。
student_ids_by_hobbies
{'映画': [0, 2, 3, 4, 7],
'読書': [0, 2, 6],
'ジョギング': [0, 1, 8, 9],
'パソコン': [0, 2, 4, 5],
'音楽鑑賞': [1, 5, 8],
'料理': [1],
'キャンプ': [2, 6],
'猫': [3, 6, 7],
'旅行': [7, 9]}
共通の趣味を持つ友達の友達をマッチング
では、最終的に友達の友達で共通の趣味を持つ部員同士をマッチングしてみます。
まず、各部員と友達の友達ペアを作ります。
student_fof_pairs =[]
for student_id in range(len(students)):
for fof_id in fof_lists[student_id]:
student_fof_pair = [student_id, fof_id]
student_fof_pairs.append(student_fof_pair)
print(student_fof_pairs)
- 空のリスト
student_fof_pairs
を作成します for
ループを2重に用いて、各学生とその友達の組み合わせを生成します。 外側のfor
ループは、range(len(students))
を指定することによって、学生の数だけ実行されます。- 内側の
for
ループでは、リストfof_lists
内に格納された各学生の友達リストを取り出しています。 具体的には、fof_lists[student_id]
と書くことで、学生student_id
の友達リストを取得しています。 - その後、
student_id
とfof_id
を要素として持つリストstudent_fof_pair
を作成し、リストstudent_fof_pairs
に追加しています。
実行すると以下の様にそれぞれの部員とその友達の友達リストができました。
[[0, 3], [0, 5], [0, 7], [1, 2], [1, 4], [1, 5], [2, 1], [2, 4], [2, 6], [2, 8], [2, 9], [3, 0], [3, 6], [3, 7], [3, 8], [3, 9], [4, 1], [4, 2], [4, 6], [4, 7], [4, 8], [4, 9], [5, 0], [5, 1], [6, 9], [6, 2], [6, 3], [6, 4], [7, 0], [7, 3], [7, 4], [7, 8], [7, 9], [8, 2], [8, 3], [8, 4], [8, 7], [9, 2], [9, 3], [9, 4], [9, 6], [9, 7]]
次に、同じ趣味を持つ部員のペアを作ります。
hobbies_ids = []
for value in student_ids_by_hobbies.values():
hobbies_ids.append(value)
from itertools import combinations
hobby_pair_lists = []
for sublist in hobbies_ids:
if len(sublist) >= 2:
pairs = list(combinations(sublist, 2))
hobby_pair_lists.extend(list(set(p) for p in pairs))
print(hobby_pair_lists)
- 最初に、
hobbies_ids
という空のリストを用意します。 for
ループを使い、student_ids_by_hobbies
という辞書型データの各値を取り出し、hobbies_ids
というリストに追加しています。student_ids_by_hobbies
データは、キーに趣味を、値にその趣味を持つ学生のIDリストが格納された辞書です。 ループ中では、values()
メソッドを使い、各趣味のリストを取り出し、append()
メソッドを使ってhobbies_ids
に追加しています。itertools
モジュールからcombinations
関数を取り込んでいます。combinations
関数は、リストなどのイテラブルオブジェクトから、指定した長さの組み合わせを返す関数です。for
ループを用いて、先に作成したリストhobbies_ids
内のリストに対して処理を行います。if
文によって、リスト内の要素数が2つ以上である場合にのみ、処理を実行します。list(combinations(sublist, 2))
は、サブリスト内の要素から2つを選んで作られる組み合わせをリストにしています。2を指定することで、2つの要素の組み合わせを生成しています。hobby_pair_lists.extend(list(set(p) for p in pairs))
は、新しい作成した組み合わせのリストpairs
内の各要素について、重複を取り除いた上で、リストhobby_pair_lists
に追加しています。このとき、リスト内包表記を使って、set()
関数で重複を取り除いた後に、リストを作成しています。
こちらを実行すると共通の趣味を持つ部員ペアが出力されます。
[{0, 2}, {0, 3}, {0, 4}, {0, 7}, {2, 3}, {2, 4}, {2, 7}, {3, 4}, {3, 7}, {4, 7}, {0, 2}, {0, 6}, {2, 6}, {0, 1}, {0, 8}, {0, 9}, {8, 1}, {1, 9}, {8, 9}, {0, 2}, {0, 4}, {0, 5}, {2, 4}, {2, 5}, {4, 5}, {1, 5}, {8, 1}, {8, 5}, {2, 6}, {3, 6}, {3, 7}, {6, 7}, {9, 7}]
最後に"student_fof_pairs"と"hobby_pair_lists"に共通するペアを探せば、「共通の趣味を持つ友達の友達」が出力されますね。
common_elements = []
for pair1 in student_fof_pairs:
for pair2 in hobby_pair_lists:
if set(pair1) == pair2:
common_elements.append(pair1)
print(common_elements)
- 空のリスト
common_elements
を作成します for
ループを2重に用いて、学生の友達リストと趣味の組み合わせリストに共通する要素を抽出します。 外側のfor
ループでは、学生の友達リスト内の学生と友達の組み合わせを取り出します。- 内側の
for
ループでは、趣味の組み合わせリスト内の要素・リストを取り出します。 そして、if
文で、取り出した2つのリストが等しいかどうかを調べています。 - 等しい場合、リスト
common_elements
に対して、append()
メソッドを使用し、学生の友達リストのペアを追加します。
結果は以下の様になります。
[[0, 3], [0, 5], [0, 7],
[1, 5],
[2, 4], [2, 4], [2, 6], [2, 6],
[3, 0], [3, 6], [3, 7], [3, 7],
[4, 2], [4, 2], [4, 7],
[5, 0], [5, 1],
[6, 2], [6, 2], [6, 3],
[7, 0], [7, 3], [7, 3], [7, 4], [7, 9],
[9, 7]]
これで、各部員と共通の趣味を持つ友達の友達ペアができました!
お互いに共通の友達や共通の趣味を持っていると仲良くなりやすいですね。
まとめ
今回はPythonを使ってマッチングを試みてみました。少しコードが回りくどい感じになりましたが、読んでいただいた方が楽しんでいコードを学んで頂けたり、何かのヒントになれば幸いです。
コメント