[Data, the Humanist's New Best Friend](index.ipynb)
*Assignment 3*
Facebook Recommendations

Facebook has been around for the past 10 years. Since the, it grew to have more than 1.3 billion active users, that is 1 out 7 people in the world has an account and is active on Facebook. Although the demographics of Facebook is getting old, we need to know that some other social networks popular among young people also belong to Facebook Inc., such as WhatsApp or Instragram. But the importance of Facebook is not trivial, as it helped establish and expand the general conception of social network analysis.

A 2014 study of "Emotional Contagion Through Social Networks" manipulated the balance of positive and negative messages seen by 689,000 Facebook users. The researchers concluded that they had found "some of the first experimental evidence to support the controversial claims that emotions can spread throughout a network, [though] the effect sizes from the manipulations are small."

In this assignment you will explore a social network in Facebook to determine who are the key players and how they act.


*Don't even bother*

The goal will be to analyze a real social network.

Assignment

Your mission will be to complete the Python code in the cells below and execute it until the output looks similar or identical to the output shown. I would recommend to use a temporary notebook to work with the dataset, and when the code is ready and producing the expected output, copypaste it to this notebook. Once is done and validated, just copy the file elsewhere, as the notebook will be the only file to be sent for evaluation. Of course, everything starts by downloading this notebook.

*One more time, no need to worry for exams here*

Deadline

April $7^{th}$.

Data

Until very recently, any Facebook user could download his or her own Facebook ego-network. In January of 2015, and according to their new platform policies, Facebook suspended the application that allowed it, making it really hard for a user to extract his/her own data. For that reason, instead of using your very own social network for this assignment, we will be using an already provived and anonymized network. Not even half the fun, but still interesting to study. The data is available as an edge lists file in facebook_combined.txt.


In [1]:
# Nothing to change in this cell
%matplotlib inline
import matplotlib.pyplot as plt
import networkx as nx
import numpy as np
import pandas as pd
import requests

# Set some options
plt.rcParams['figure.figsize'] = (12.0, 6.0)
pd.set_option('display.max_columns', 20)
pd.set_option('display.max_rows', 25)

Preparation

Let's just load the data and show number of nodes and relationships.


In [2]:
facebook = nx...
facebook..., facebook...


Out[2]:
(88234, 4039)

Analysis

Using Networkx, let's compute the 5 Facebook friend with the highest degree centrality, the number of components in the Facebook network, and the average clustering coefficient and average shortest path length of the network or of the largest component.


In [3]:
degrees = nx..
sorted(degrees.items(), key=lambda x: x[1], reverse=True)[:5]


Out[3]:
[('107', 0.258791480931154),
 ('1684', 0.1961367013372957),
 ('1912', 0.18697374938088163),
 ('3437', 0.13546310054482416),
 ('0', 0.08593363051015354)]

In [4]:
len(list(nx...))


Out[4]:
1

In [5]:
nx...


Out[5]:
0.605546718620086

In [6]:
nx...


Out[6]:
3.6925068496963913

By looking at the numbers, it might seem like this Facebook graph is following a small-world model. If that is the case, there should be tightly knit cliques connected by weak ties. Let's see then the global clustering coefficient (transitivity).


In [7]:
nx...


Out[7]:
0.5191742775433075

In order to calculate the communities, we will use the Louvain community detection library. The main and only file you need is community.py, so download it and put it where this notebook can read it. The next cell will look for the file in the current environment, if that doesn't work it will try to fetch the file automatically.


In [8]:
# Nothing to change in this cell
try:
    import community
except ImportError:
    import imp
    import sys

    community = sys.modules["community"] = imp.new_module("community")
    community.__file__ = "https://bitbucket.org/taynaud/python-louvain/raw/default/community/__init__.py"
    exec(requests.get(community.__file__).text, community.__dict__)

community


Out[8]:
<module 'community' from 'https://bitbucket.org/taynaud/python-louvain/raw/default/community/__init__.py'>

Once the library is loaded, let's calculate the number of communities. The way it works is by calculating the best partition for the graph. Then it returns a dictionary with nodes as keys and the community number as values. Given that information, let's extract the biggest and the smallest communities. First let's create a dictionary with the number of nodes per community, and print it sorted by the the number of nodes.


In [9]:
partition = community.best_partition(facebook)
communities = {}
for i in set(partition.values()):
    communities[i] = ...
communities


Out[9]:
{0: 425,
 1: 350,
 2: 446,
 3: 548,
 4: 117,
 5: 429,
 6: 60,
 7: 535,
 8: 226,
 9: 206,
 10: 236,
 11: 325,
 12: 25,
 13: 19,
 14: 73,
 15: 19}

In [10]:
sorted_communities = ...
for community_id, nodes in sorted_communities:
    print("Community {:2.0f}: {:3.0f} nodes".format(community_id, nodes))


Community 13:  19 nodes
Community 15:  19 nodes
Community 12:  25 nodes
Community  6:  60 nodes
Community 14:  73 nodes
Community  4: 117 nodes
Community  9: 206 nodes
Community  8: 226 nodes
Community 10: 236 nodes
Community 11: 325 nodes
Community  1: 350 nodes
Community  0: 425 nodes
Community  5: 429 nodes
Community  2: 446 nodes
Community  7: 535 nodes
Community  3: 548 nodes

Once we have the communities, let's print the members for the biggest and the smallest. But two communities have the same amount of nodes, so we will print both of them.


In [11]:
# We need to use partition again!
# this list will contain 3 numbers, although depending on the machine, the might be different to the ones shown below
for community_id in [...]:
    nodes = ...
    print("Community {}:".format(community_id), nodes)


Community 13: ['2076', '1924', '2622', '2426', '2320', '2170', '1988', '2515', '2349', '2486', '1992', '2466', '2401', '2207', '2490', '2444', '2255', '2513', '2650']
Community 15: ['3008', '2703', '2699', '2670', '3318', '2879', '3283', '3311', '2959', '3309', '2982', '3314', '2889', '3382', '2834', '2767', '3325', '3423', '2972']
Community 1: ['310', '80', '287', '12', '339', '166', '28', '182', '14', '292', '206', '112', '68', '320', '178', '188', '36', '283', '143', '155', '50', '47', '277', '8', '306', '305', '40', '62', '90', '93', '276', '343', '137', '171', '270', '308', '127', '145', '17', '331', '116', '340', '84', '135', '338', '125', '33', '148', '154', '328', '323', '272', '344', '210', '239', '113', '268', '319', '55', '207', '224', '218', '42', '39', '51', '13', '120', '94', '110', '106', '191', '6', '78', '11', '229', '3', '223', '220', '157', '243', '132', '23', '130', '21', '2704', '288', '126', '88', '264', '194', '211', '291', '189', '129', '76', '266', '144', '156', '152', '255', '1', '246', '262', '221', '256', '309', '324', '190', '234', '59', '228', '252', '347', '274', '183', '254', '87', '9', '267', '269', '204', '314', '103', '123', '286', '299', '151', '147', '342', '326', '35', '44', '18', '92', '327', '233', '185', '108', '91', '195', '22', '30', '121', '63', '346', '96', '164', '232', '238', '294', '226', '104', '111', '235', '105', '332', '172', '263', '330', '311', '315', '170', '163', '236', '7', '115', '298', '46', '213', '313', '128', '261', '334', '333', '101', '48', '209', '250', '167', '241', '341', '295', '196', '98', '293', '138', '60', '134', '325', '179', '3003', '225', '335', '118', '61', '74', '79', '257', '85', '303', '99', '20', '275', '4', '230', '149', '45', '174', '215', '200', '203', '301', '260', '317', '31', '251', '158', '237', '53', '82', '159', '180', '26', '279', '201', '38', '16', '193', '24', '199', '253', '337', '192', '208', '168', '64', '142', '307', '124', '153', '273', '282', '329', '300', '141', '284', '222', '100', '247', '10', '169', '25', '41', '43', '19', '81', '57', '217', '66', '316', '83', '3290', '280', '181', '227', '281', '150', '75', '197', '258', '2814', '271', '242', '186', '160', '321', '29', '114', '184', '86', '249', '345', '69', '122', '259', '244', '109', '139', '205', '37', '102', '58', '117', '65', '312', '240', '73', '175', '146', '71', '289', '77', '202', '89', '27', '297', '0', '322', '67', '187', '119', '216', '165', '177', '72', '302', '97', '133', '95', '70', '212', '278', '219', '2740', '231', '5', '245', '304', '54', '32', '140', '2838', '56', '290', '2', '15', '52', '336', '176', '285', '49', '318', '161', '248', '131', '214', '2885', '296', '265', '162']
*Late, Hagrid, late*

Visualizations

Let's now see how the smallest communities look like.


In [12]:
small_community_1_nodes = ...
subgraph = facebook...
nx...



In [13]:
small_community_1_nodes = ...
subgraph = facebook...
nx...


And for the list of nodes in the biggest community, let's sort the nodes by the total degree-centrality, clustering, and betweenness centrality. Show only the first 10.


In [14]:
big_community_nodes = ...

In [15]:
degree = nx...
sorted_degree = ...
for node_id, value in sorted_degree[:10]:
    print("{}: {}".format(node_id, value))


0: 0.08593363051015354
56: 0.019316493313521546
67: 0.018821198613174838
271: 0.018078256562654778
322: 0.017830609212481426
25: 0.017087667161961365
26: 0.016840019811788013
277: 0.016097077761267953
21: 0.016097077761267953
252: 0.016097077761267953

In [16]:
clustering = nx...(..., nodes=big_community_nodes)
sorted_clustering = ...
for node_id, value in sorted_clustering[:10]:
    print("{}: {}".format(node_id, value))


264: 1.0
154: 1.0
328: 1.0
44: 1.0
160: 1.0
241: 1.0
327: 1.0
201: 1.0
216: 1.0
3003: 1.0

In [17]:
centrality = nx...(..., k=len(big_community_nodes))
sorted_centrality = ...
for node_id, value in sorted_centrality[:10]:
    print("{}: {}".format(node_id, value))


0: 0.14857039413111853
58: 0.07796992610952065
171: 0.014785102147682782
119: 0.001778975037940118
122: 0.0009261476446850848
56: 0.0008553131990364182
322: 0.0008031053756412232
67: 0.0007811400780509631
21: 0.0006900930586130221
304: 0.0005775062332880885

For the nodes with the highest degree let's plot their ego-network of radius 2.


In [18]:
nx...


For the nodes with the highest clustering coeffient (any if more than one) let's plot their ego-network of radius 3.


In [19]:
nx...


For the highest betweenness with radius 1.


In [20]:
nx...


And also let's plot the degree distribution of the total graph.


In [21]:
degree_hist = plt...
plt.loglog(..., ...)
plt...


Out[21]:
<matplotlib.text.Text at 0x7f77335a18d0>

Recommendations

Facebook suggests people you may be (or should be) friends with. Netflix suggests movies you might like. Amazon suggests products to buy. How do they do that? Although, the actual algorithms used by these companies are closely-guarded trade secrets, we will try now one simple way to make such suggestions called "collaborative filtering".

A computer system that makes suggestions is called a recommender system. As background, there are two general approaches: collaborative filtering and content-based filtering.

  • Collaborative filtering says that, if your past behavior/preferences were similar to some other user's, then your future behavior may be as well. As a concrete example, suppose that you like John, Paul, and George, and other people like John, Paul, George, and Ringo. Then it stands to reason that you will like Ringo as well, even if you had never previously heard of him. The recommender system does not have to understand anything about what “John”, “Paul”, “George”, and “Ringo” are — they could even be brands of toilet paper, and the algorithm would work identically.
  • Content-based filtering considers the characteristics of the things you like, and it recommends similar sorts of things. For instance, if you like “Billie Jean”, “Crazy Train”, and “Don't Stop the Music”, then you might like other songs in the key of F-sharp minor, such as Rachmaninoff's “Piano Concerto No. 1”, even if no one else has ever had that particular set of favorite songs before.

Let's implement one those mechanisms for recommending a new friend in a social network. A simple way to state this question is, "For user X, who is the best person to recommend as a friend?" Which is the same as "For user X, list some non-friends in order, starting with the best friend recommendation and ending with the worst." A non-friend is a user who is not X and is not a friend of X. Depending on the recommendation algorithm, the list may include all non-friends or some of them. You will do this by assigning each potential friend a number called a score, where higher scores indicate a better match. Then you can sort your list according to the score.

Recommend by number of common friends

If non-friend Y is your friend's friend, then maybe Y should be your friend too. If person Y is the friend of many of your friends, then Y is an even better recommendation. The best friend recommendation is the person with whom you have the largest number of mutual friends. You will implement this heuristic.

Let's say we are interested in giving "A" recommendations of people that they might want to be friends with. By this algorithm, the number of friends you have in common with someone is a measure of how likely it is that they would be a good friend recommendation for you. Thus the more friends someone has in common with you, the better their "friendship score" is. We will actually use the number of friends in common as the friendship score itself. Thus we want to find out who has the most friends in common with "A". If we had:

  • A has one friend in common with B (namely, C).
  • A has one friend in common with C (namely, B).
  • A has two friends in common with D (namely, B and C).
  • A has no friends in common with E.
  • A has one friend in common with F (namely, C).

D is the best recommendation for A, F is the second best recommendation. We would not recommend B or C because A is already friends with them. We also would not recommend E because A has no friends in common with E.

Now let's think about how we might create this list. Obviously we will need to calculate these "friendship scores" for some set of people in the graph. By this "number of common friends" metric, for a given person, we really only care about calculating such scores for people that are "friends of our current friends" who are not yet our friends. (There could be many people in a large graph, so we do not want to simply calculate friendship scores for every person in the graph as many of those scores are likely to be zero.) So it would be useful to be able to calculate the set of "friends of friends" for a given user.

We will use the node with id "0" in the facebook graph as our user.


In [22]:
def friends_of_friends(graph, user):
    """Returns a set of friends of friends of the given user, in the given graph.
    The result does not include the given user nor any of that user's friends.
    """
    ego_nodes_r2 = ...
    ego_nodes_r1 = ...
    return ... - ... - ...
    

friends_of_friends(facebook, "0")


Out[22]:
{'1000',
 '1001',
 '1002',
 '1003',
 '1004',
 '1005',
 '1006',
 '1007',
 '1008',
 '1009',
 '1010',
 '1011',
 '1012',
 '1013',
 '1014',
 '1015',
 '1016',
 '1017',
 '1018',
 '1019',
 '1020',
 '1021',
 '1022',
 '1023',
 '1024',
 '1025',
 '1026',
 '1027',
 '1028',
 '1029',
 '1030',
 '1031',
 '1032',
 '1033',
 '1034',
 '1035',
 '1036',
 '1037',
 '1038',
 '1039',
 '1040',
 '1041',
 '1042',
 '1043',
 '1044',
 '1045',
 '1046',
 '1047',
 '1048',
 '1049',
 '1050',
 '1051',
 '1052',
 '1053',
 '1054',
 '1055',
 '1056',
 '1057',
 '1058',
 '1059',
 '1060',
 '1061',
 '1062',
 '1063',
 '1064',
 '1065',
 '1066',
 '1067',
 '1068',
 '1069',
 '1070',
 '1071',
 '1072',
 '1073',
 '1074',
 '1075',
 '1076',
 '1077',
 '1078',
 '1079',
 '1080',
 '1081',
 '1082',
 '1083',
 '1084',
 '1085',
 '1086',
 '1087',
 '1088',
 '1089',
 '1090',
 '1091',
 '1092',
 '1093',
 '1094',
 '1095',
 '1096',
 '1097',
 '1098',
 '1099',
 '1100',
 '1101',
 '1102',
 '1103',
 '1104',
 '1105',
 '1106',
 '1107',
 '1108',
 '1109',
 '1110',
 '1111',
 '1112',
 '1113',
 '1114',
 '1115',
 '1116',
 '1117',
 '1118',
 '1119',
 '1120',
 '1121',
 '1122',
 '1123',
 '1124',
 '1125',
 '1126',
 '1127',
 '1128',
 '1129',
 '1130',
 '1131',
 '1132',
 '1133',
 '1134',
 '1135',
 '1136',
 '1137',
 '1138',
 '1139',
 '1140',
 '1141',
 '1142',
 '1143',
 '1144',
 '1145',
 '1146',
 '1147',
 '1148',
 '1149',
 '1150',
 '1151',
 '1152',
 '1153',
 '1154',
 '1155',
 '1156',
 '1157',
 '1158',
 '1159',
 '1160',
 '1161',
 '1162',
 '1163',
 '1164',
 '1165',
 '1166',
 '1167',
 '1168',
 '1169',
 '1170',
 '1171',
 '1172',
 '1173',
 '1174',
 '1175',
 '1176',
 '1177',
 '1178',
 '1179',
 '1180',
 '1181',
 '1182',
 '1183',
 '1184',
 '1185',
 '1186',
 '1187',
 '1188',
 '1189',
 '1190',
 '1191',
 '1192',
 '1193',
 '1194',
 '1195',
 '1196',
 '1197',
 '1198',
 '1199',
 '1200',
 '1201',
 '1202',
 '1203',
 '1204',
 '1205',
 '1206',
 '1207',
 '1208',
 '1209',
 '1210',
 '1211',
 '1212',
 '1213',
 '1214',
 '1215',
 '1216',
 '1217',
 '1218',
 '1219',
 '1220',
 '1221',
 '1222',
 '1223',
 '1224',
 '1225',
 '1226',
 '1227',
 '1228',
 '1229',
 '1230',
 '1231',
 '1232',
 '1233',
 '1234',
 '1235',
 '1236',
 '1237',
 '1238',
 '1239',
 '1240',
 '1241',
 '1242',
 '1243',
 '1244',
 '1245',
 '1246',
 '1247',
 '1248',
 '1249',
 '1250',
 '1251',
 '1252',
 '1253',
 '1254',
 '1255',
 '1256',
 '1257',
 '1258',
 '1259',
 '1260',
 '1261',
 '1262',
 '1263',
 '1264',
 '1265',
 '1266',
 '1267',
 '1268',
 '1269',
 '1270',
 '1271',
 '1272',
 '1273',
 '1274',
 '1275',
 '1276',
 '1277',
 '1278',
 '1279',
 '1280',
 '1281',
 '1282',
 '1283',
 '1284',
 '1285',
 '1286',
 '1287',
 '1288',
 '1289',
 '1290',
 '1291',
 '1292',
 '1293',
 '1294',
 '1295',
 '1296',
 '1297',
 '1298',
 '1299',
 '1300',
 '1301',
 '1302',
 '1303',
 '1304',
 '1305',
 '1306',
 '1307',
 '1308',
 '1309',
 '1310',
 '1311',
 '1312',
 '1313',
 '1314',
 '1315',
 '1316',
 '1317',
 '1318',
 '1319',
 '1320',
 '1321',
 '1322',
 '1323',
 '1324',
 '1325',
 '1326',
 '1327',
 '1328',
 '1329',
 '1330',
 '1331',
 '1332',
 '1333',
 '1334',
 '1335',
 '1336',
 '1337',
 '1338',
 '1339',
 '1340',
 '1341',
 '1342',
 '1343',
 '1344',
 '1345',
 '1346',
 '1347',
 '1348',
 '1349',
 '1350',
 '1351',
 '1352',
 '1353',
 '1354',
 '1355',
 '1356',
 '1357',
 '1358',
 '1359',
 '1360',
 '1361',
 '1362',
 '1363',
 '1364',
 '1365',
 '1366',
 '1367',
 '1368',
 '1369',
 '1370',
 '1371',
 '1372',
 '1373',
 '1374',
 '1375',
 '1376',
 '1377',
 '1378',
 '1379',
 '1380',
 '1381',
 '1382',
 '1383',
 '1384',
 '1385',
 '1386',
 '1387',
 '1388',
 '1389',
 '1390',
 '1391',
 '1392',
 '1393',
 '1394',
 '1395',
 '1396',
 '1397',
 '1398',
 '1399',
 '1400',
 '1401',
 '1402',
 '1403',
 '1404',
 '1405',
 '1406',
 '1407',
 '1408',
 '1409',
 '1410',
 '1411',
 '1412',
 '1413',
 '1414',
 '1415',
 '1416',
 '1417',
 '1418',
 '1419',
 '1420',
 '1421',
 '1422',
 '1423',
 '1424',
 '1425',
 '1426',
 '1427',
 '1428',
 '1429',
 '1430',
 '1431',
 '1432',
 '1433',
 '1434',
 '1435',
 '1436',
 '1437',
 '1438',
 '1439',
 '1440',
 '1441',
 '1442',
 '1443',
 '1444',
 '1445',
 '1446',
 '1447',
 '1448',
 '1449',
 '1450',
 '1451',
 '1452',
 '1453',
 '1454',
 '1455',
 '1456',
 '1457',
 '1458',
 '1459',
 '1460',
 '1461',
 '1462',
 '1463',
 '1464',
 '1465',
 '1466',
 '1467',
 '1468',
 '1469',
 '1470',
 '1471',
 '1472',
 '1473',
 '1474',
 '1475',
 '1476',
 '1477',
 '1478',
 '1479',
 '1480',
 '1481',
 '1482',
 '1483',
 '1484',
 '1485',
 '1486',
 '1487',
 '1488',
 '1489',
 '1490',
 '1491',
 '1492',
 '1493',
 '1494',
 '1495',
 '1496',
 '1497',
 '1498',
 '1499',
 '1500',
 '1501',
 '1502',
 '1503',
 '1504',
 '1505',
 '1506',
 '1507',
 '1508',
 '1509',
 '1510',
 '1511',
 '1512',
 '1513',
 '1514',
 '1515',
 '1516',
 '1517',
 '1518',
 '1519',
 '1520',
 '1521',
 '1522',
 '1523',
 '1524',
 '1525',
 '1526',
 '1527',
 '1528',
 '1529',
 '1530',
 '1531',
 '1532',
 '1533',
 '1534',
 '1535',
 '1536',
 '1537',
 '1538',
 '1539',
 '1540',
 '1541',
 '1542',
 '1543',
 '1544',
 '1545',
 '1546',
 '1547',
 '1548',
 '1549',
 '1550',
 '1551',
 '1552',
 '1553',
 '1554',
 '1555',
 '1556',
 '1557',
 '1558',
 '1559',
 '1560',
 '1561',
 '1562',
 '1563',
 '1564',
 '1565',
 '1566',
 '1567',
 '1568',
 '1569',
 '1570',
 '1571',
 '1572',
 '1573',
 '1574',
 '1575',
 '1576',
 '1577',
 '1578',
 '1579',
 '1580',
 '1581',
 '1582',
 '1583',
 '1584',
 '1585',
 '1586',
 '1587',
 '1588',
 '1589',
 '1590',
 '1591',
 '1592',
 '1593',
 '1594',
 '1595',
 '1596',
 '1597',
 '1598',
 '1599',
 '1600',
 '1601',
 '1602',
 '1603',
 '1604',
 '1605',
 '1606',
 '1607',
 '1608',
 '1609',
 '1610',
 '1611',
 '1612',
 '1613',
 '1614',
 '1615',
 '1616',
 '1617',
 '1618',
 '1619',
 '1620',
 '1621',
 '1622',
 '1623',
 '1624',
 '1625',
 '1626',
 '1627',
 '1628',
 '1629',
 '1630',
 '1631',
 '1632',
 '1633',
 '1634',
 '1635',
 '1636',
 '1637',
 '1638',
 '1639',
 '1640',
 '1641',
 '1642',
 '1643',
 '1644',
 '1645',
 '1646',
 '1647',
 '1648',
 '1649',
 '1650',
 '1651',
 '1652',
 '1653',
 '1654',
 '1655',
 '1656',
 '1657',
 '1658',
 '1659',
 '1660',
 '1661',
 '1662',
 '1663',
 '1664',
 '1665',
 '1666',
 '1667',
 '1668',
 '1669',
 '1670',
 '1671',
 '1672',
 '1673',
 '1674',
 '1675',
 '1676',
 '1677',
 '1678',
 '1679',
 '1680',
 '1681',
 '1682',
 '1683',
 '1684',
 '1685',
 '1686',
 '1687',
 '1688',
 '1689',
 '1690',
 '1691',
 '1692',
 '1693',
 '1694',
 '1695',
 '1696',
 '1697',
 '1698',
 '1699',
 '1700',
 '1701',
 '1702',
 '1703',
 '1704',
 '1705',
 '1706',
 '1707',
 '1708',
 '1709',
 '1710',
 '1711',
 '1712',
 '1713',
 '1714',
 '1715',
 '1716',
 '1717',
 '1718',
 '1719',
 '1720',
 '1721',
 '1722',
 '1723',
 '1724',
 '1725',
 '1726',
 '1727',
 '1728',
 '1729',
 '1730',
 '1731',
 '1732',
 '1733',
 '1734',
 '1735',
 '1736',
 '1737',
 '1738',
 '1739',
 '1740',
 '1741',
 '1742',
 '1743',
 '1744',
 '1745',
 '1746',
 '1747',
 '1748',
 '1749',
 '1750',
 '1751',
 '1752',
 '1753',
 '1754',
 '1755',
 '1756',
 '1757',
 '1758',
 '1759',
 '1760',
 '1761',
 '1762',
 '1763',
 '1764',
 '1765',
 '1766',
 '1767',
 '1768',
 '1769',
 '1770',
 '1771',
 '1772',
 '1773',
 '1774',
 '1775',
 '1776',
 '1777',
 '1778',
 '1779',
 '1780',
 '1781',
 '1782',
 '1783',
 '1784',
 '1785',
 '1786',
 '1787',
 '1788',
 '1789',
 '1790',
 '1791',
 '1792',
 '1793',
 '1794',
 '1795',
 '1796',
 '1797',
 '1798',
 '1799',
 '1800',
 '1801',
 '1802',
 '1803',
 '1804',
 '1805',
 '1806',
 '1807',
 '1808',
 '1809',
 '1810',
 '1811',
 '1812',
 '1813',
 '1814',
 '1815',
 '1816',
 '1817',
 '1818',
 '1819',
 '1820',
 '1821',
 '1822',
 '1823',
 '1824',
 '1825',
 '1826',
 '1827',
 '1828',
 '1829',
 '1830',
 '1831',
 '1832',
 '1833',
 '1834',
 '1835',
 '1836',
 '1837',
 '1838',
 '1839',
 '1840',
 '1841',
 '1842',
 '1843',
 '1844',
 '1845',
 '1846',
 '1847',
 '1848',
 '1849',
 '1850',
 '1851',
 '1852',
 '1853',
 '1854',
 '1855',
 '1856',
 '1857',
 '1858',
 '1859',
 '1860',
 '1861',
 '1862',
 '1863',
 '1864',
 '1865',
 '1866',
 '1867',
 '1868',
 '1869',
 '1870',
 '1871',
 '1872',
 '1873',
 '1874',
 '1875',
 '1876',
 '1877',
 '1878',
 '1879',
 '1880',
 '1881',
 '1882',
 '1883',
 '1884',
 '1885',
 '1886',
 '1887',
 '1888',
 '1889',
 '1890',
 '1891',
 '1892',
 '1893',
 '1894',
 '1895',
 '1896',
 '1897',
 '1898',
 '1899',
 '1900',
 '1901',
 '1902',
 '1903',
 '1904',
 '1905',
 '1906',
 '1907',
 '1908',
 '1909',
 '1910',
 '1911',
 '1912',
 '1926',
 '1932',
 '1939',
 '1945',
 '1951',
 '1955',
 '1972',
 '1973',
 '1976',
 '1991',
 '1995',
 '1998',
 '2001',
 '2004',
 '2007',
 '2009',
 '2018',
 '2024',
 '2027',
 '2032',
 '2038',
 '2039',
 '2042',
 '2054',
 '2068',
 '2071',
 '2072',
 '2081',
 '2102',
 '2111',
 '2116',
 '2117',
 '2127',
 '2128',
 '2133',
 '2135',
 '2138',
 '2143',
 '2153',
 '2157',
 '2171',
 '2174',
 '2180',
 '2183',
 '2187',
 '2189',
 '2199',
 '2203',
 '2223',
 '2224',
 '2225',
 '2247',
 '2250',
 '2254',
 '2264',
 '2267',
 '2268',
 '2279',
 '2283',
 '2284',
 '2289',
 '2292',
 '2302',
 '2319',
 '2327',
 '2336',
 '2337',
 '2364',
 '2378',
 '2384',
 '2398',
 '2417',
 '2436',
 '2445',
 '2447',
 '2451',
 '2458',
 '2459',
 '2461',
 '2463',
 '2471',
 '2472',
 '2475',
 '2491',
 '2494',
 '2498',
 '2502',
 ...}

For each of those friends-of-friends we will want to be able to calculate the set of friends that they have in common with the user.


In [23]:
def common_friends(graph, user1, user2):
    """Returns the set of friends that user1 and user2 have in common."""
    user1_friends = ...
    user2_friends = ...
    return ...

common_friends(facebook, "0", "100")


Out[23]:
{'119', '150', '163', '189', '217', '269', '323', '64'}

If we want to return to the user a ranked list of recommendations from best recommendation to worst, then it would be useful to have a data structure like a dictionary to keep track of the mapping of "friend of friend" to friendship score.


In [24]:
def number_of_common_friends(graph, user):
    """Returns a dictionary from each user U to the number of friends U has in common with the given user.
    The map keys are the users who have at least one friend in common with the
    given user, and are neither the given user nor one of the given user's friends.
    Take a graph G for example:
        - A and B have two friends in common
        - A and C have one friend in common
        - A and D have one friend in common
        - A and E have no friends in common
        - A is friends with D
    number_of_common_friends(G, "A")  =>   { 'B':2, 'C':1 }
    """
    common_friends_count = {}
    for fof in ...
        ...
    return common_friends_count

number_of_common_friends(facebook, "0")


Out[24]:
{'441': 1,
 '1539': 1,
 '1670': 1,
 '1420': 1,
 '1115': 1,
 '1328': 1,
 '1318': 1,
 '1590': 1,
 '1305': 1,
 '1787': 1,
 '1797': 1,
 '2117': 1,
 '2571': 1,
 '1413': 1,
 '1260': 1,
 '1852': 1,
 '2647': 1,
 '1002': 1,
 '1618': 1,
 '1423': 1,
 '2268': 1,
 '1043': 1,
 '983': 1,
 '1862': 1,
 '1901': 1,
 '1205': 1,
 '1321': 1,
 '1652': 1,
 '1326': 1,
 '1477': 1,
 '1932': 1,
 '1734': 1,
 '1799': 1,
 '1782': 1,
 '1790': 1,
 '1077': 1,
 '1149': 1,
 '1229': 1,
 '2289': 1,
 '1169': 1,
 '939': 1,
 '1253': 1,
 '2649': 1,
 '1722': 1,
 '965': 1,
 '1283': 1,
 '1011': 1,
 '1071': 1,
 '2054': 1,
 '1422': 1,
 '1271': 1,
 '1820': 1,
 '1265': 1,
 '1521': 1,
 '1607': 1,
 '1198': 1,
 '1835': 1,
 '1009': 1,
 '1738': 1,
 '1712': 1,
 '1280': 1,
 '1660': 1,
 '1246': 1,
 '1138': 1,
 '1233': 1,
 '475': 1,
 '1155': 1,
 '1532': 1,
 '1051': 1,
 '1195': 1,
 '1329': 1,
 '940': 1,
 '1201': 1,
 '1092': 1,
 '1684': 3,
 '1486': 2,
 '2538': 1,
 '1416': 1,
 '1408': 1,
 '1415': 1,
 '1726': 1,
 '1424': 1,
 '1108': 1,
 '1609': 1,
 '1081': 1,
 '1209': 1,
 '1775': 1,
 '1880': 1,
 '2039': 1,
 '1888': 1,
 '1395': 1,
 '1249': 1,
 '1439': 1,
 '1053': 1,
 '1911': 1,
 '1410': 1,
 '1691': 1,
 '2451': 1,
 '1536': 1,
 '1237': 1,
 '1494': 1,
 '1223': 1,
 '2143': 1,
 '1259': 1,
 '1299': 1,
 '1976': 1,
 '906': 1,
 '1615': 1,
 '978': 1,
 '2653': 1,
 '1682': 1,
 '2511': 1,
 '1603': 1,
 '1065': 1,
 '1354': 1,
 '1267': 1,
 '2254': 1,
 '1350': 1,
 '1517': 1,
 '1064': 1,
 '981': 1,
 '1484': 1,
 '1500': 1,
 '2292': 1,
 '1732': 1,
 '1849': 1,
 '1122': 1,
 '1024': 1,
 '1814': 1,
 '1823': 1,
 '1514': 1,
 '2007': 1,
 '1204': 1,
 '1829': 1,
 '1049': 1,
 '1721': 1,
 '1498': 1,
 '1611': 1,
 '1565': 1,
 '2027': 1,
 '1182': 1,
 '1689': 1,
 '979': 1,
 '1663': 1,
 '1342': 1,
 '1869': 1,
 '1566': 1,
 '1144': 1,
 '1584': 1,
 '1582': 1,
 '1167': 1,
 '1812': 1,
 '1844': 1,
 '1496': 1,
 '1472': 1,
 '427': 1,
 '1522': 1,
 '1327': 1,
 '1716': 1,
 '920': 1,
 '1683': 1,
 '1890': 1,
 '1474': 1,
 '1010': 1,
 '1136': 1,
 '1079': 1,
 '1465': 1,
 '998': 1,
 '1429': 1,
 '959': 1,
 '1896': 1,
 '1593': 1,
 '1060': 1,
 '1912': 2,
 '1645': 1,
 '1475': 1,
 '1802': 1,
 '1620': 1,
 '1338': 1,
 '1476': 1,
 '1031': 1,
 '1879': 1,
 '1502': 1,
 '1008': 1,
 '1579': 1,
 '1004': 1,
 '1380': 1,
 '1570': 1,
 '1939': 1,
 '1676': 1,
 '1451': 1,
 '2417': 1,
 '1066': 1,
 '1610': 1,
 '1331': 1,
 '1172': 1,
 '2127': 1,
 '1334': 1,
 '1651': 1,
 '1788': 1,
 '606': 1,
 '1056': 1,
 '1561': 1,
 '1156': 1,
 '1501': 1,
 '903': 1,
 '1839': 1,
 '1436': 1,
 '2461': 1,
 '1386': 1,
 '1070': 1,
 '1507': 1,
 '2378': 1,
 '1226': 1,
 '3003': 2,
 '1096': 1,
 '1398': 1,
 '1038': 1,
 '1756': 1,
 '376': 1,
 '1780': 1,
 '1805': 1,
 '1068': 1,
 '1135': 1,
 '1046': 1,
 '1332': 1,
 '1809': 1,
 '1945': 1,
 '989': 1,
 '1296': 1,
 '1828': 1,
 '1263': 1,
 '1567': 1,
 '926': 1,
 '1641': 1,
 '1878': 1,
 '1858': 1,
 '1447': 1,
 '967': 1,
 '2138': 1,
 '1217': 1,
 '2174': 1,
 '1571': 1,
 '1649': 1,
 '1578': 1,
 '1617': 1,
 '1119': 1,
 '601': 1,
 '1094': 1,
 '1378': 1,
 '1643': 1,
 '1789': 1,
 '1157': 1,
 '1076': 1,
 '1276': 1,
 '1899': 1,
 '1258': 1,
 '1446': 1,
 '2032': 1,
 '1184': 1,
 '1006': 1,
 '1396': 1,
 '1824': 1,
 '969': 1,
 '1297': 2,
 '1027': 1,
 '1266': 1,
 '2072': 1,
 '1848': 1,
 '1715': 1,
 '1855': 1,
 '1666': 1,
 '1457': 1,
 '1573': 1,
 '1576': 1,
 '1113': 1,
 '897': 1,
 '990': 1,
 '1300': 1,
 '1490': 1,
 '1739': 1,
 '1728': 1,
 '1221': 1,
 '1018': 1,
 '1432': 1,
 '1972': 1,
 '1508': 1,
 '1837': 1,
 '1847': 1,
 '1349': 1,
 '564': 1,
 '1842': 1,
 '1301': 1,
 '1544': 1,
 '1397': 1,
 '1425': 1,
 '1499': 1,
 '1871': 1,
 '918': 1,
 '1537': 1,
 '1294': 1,
 '2598': 1,
 '1042': 1,
 '428': 2,
 '1562': 1,
 '1344': 1,
 '1107': 1,
 '955': 1,
 '1330': 1,
 '1158': 1,
 '900': 1,
 '1893': 1,
 '1367': 1,
 '2279': 1,
 '1161': 1,
 '2224': 1,
 '1417': 1,
 '1110': 1,
 '1450': 1,
 '2004': 1,
 '1261': 1,
 '1240': 1,
 '1825': 1,
 '1851': 1,
 '1262': 1,
 '1843': 1,
 '1188': 1,
 '993': 1,
 '1164': 1,
 '1760': 1,
 '1255': 1,
 '1529': 1,
 '1016': 1,
 '1777': 1,
 '1202': 1,
 '1099': 1,
 '1714': 1,
 '1362': 1,
 '1244': 1,
 '1991': 1,
 '1448': 1,
 '2189': 1,
 '1100': 1,
 '1104': 1,
 '1485': 1,
 '1616': 1,
 '1882': 1,
 '1014': 1,
 '1361': 1,
 '1251': 1,
 '2589': 1,
 '2436': 1,
 '1125': 1,
 '1289': 1,
 '1150': 1,
 '1460': 1,
 '976': 1,
 '1320': 1,
 '1870': 1,
 '1288': 1,
 '1798': 1,
 '1072': 1,
 '919': 1,
 '1656': 1,
 '1353': 1,
 '1857': 1,
 '2247': 1,
 '1388': 1,
 '399': 1,
 '1000': 1,
 '1020': 1,
 '2081': 1,
 '943': 1,
 '1973': 1,
 '1681': 1,
 '938': 1,
 '1771': 1,
 '1405': 1,
 '1421': 1,
 '953': 1,
 '1811': 1,
 '1348': 1,
 '1677': 1,
 '1736': 1,
 '952': 1,
 '977': 1,
 '961': 1,
 '1792': 1,
 '2502': 1,
 '1678': 1,
 '1019': 1,
 '1437': 1,
 '526': 1,
 '2364': 1,
 '1013': 1,
 '1909': 1,
 '2264': 1,
 '1428': 1,
 '1214': 1,
 '1534': 1,
 '1650': 1,
 '1585': 1,
 '2157': 1,
 '1069': 1,
 '1145': 1,
 '1757': 1,
 '1287': 1,
 '1520': 1,
 '1492': 1,
 '1675': 1,
 '1581': 1,
 '1662': 1,
 '1456': 1,
 '1747': 1,
 '1545': 1,
 '1333': 1,
 '1272': 1,
 '1881': 1,
 '1910': 1,
 '1412': 1,
 '414': 3,
 '999': 1,
 '1359': 1,
 '1086': 1,
 '566': 1,
 '911': 1,
 '917': 1,
 '1755': 1,
 '1538': 1,
 '1808': 1,
 '1383': 1,
 '1376': 1,
 '2042': 1,
 '1867': 1,
 '1401': 1,
 '596': 1,
 '1082': 1,
 '1810': 1,
 '1735': 1,
 '1815': 1,
 '1225': 1,
 '1535': 1,
 '1598': 1,
 '1041': 1,
 '1696': 1,
 '464': 1,
 '1431': 1,
 '1671': 1,
 '1127': 1,
 '1605': 1,
 '1866': 1,
 '991': 1,
 '1382': 1,
 '932': 1,
 '1568': 1,
 '1763': 1,
 '1111': 1,
 '1637': 1,
 '1187': 1,
 '1495': 1,
 '1193': 2,
 '1555': 1,
 '1245': 1,
 '1638': 1,
 '1601': 1,
 '1776': 1,
 '641': 1,
 '902': 1,
 '1595': 1,
 '1243': 1,
 '1059': 1,
 '982': 1,
 '1762': 1,
 '915': 1,
 '1054': 1,
 '1718': 2,
 '1325': 1,
 '929': 1,
 '1385': 1,
 '1483': 1,
 '1885': 1,
 '1639': 1,
 '985': 1,
 '1285': 1,
 '1365': 1,
 '913': 1,
 '393': 1,
 '1355': 1,
 '994': 1,
 '923': 1,
 '936': 1,
 '2472': 1,
 '1073': 1,
 '1482': 1,
 '1859': 1,
 '1542': 1,
 '2475': 1,
 '1279': 1,
 '1390': 1,
 '1531': 1,
 '1384': 1,
 '1232': 1,
 '1768': 1,
 '1634': 1,
 '1126': 1,
 '1473': 1,
 '1746': 1,
 '2302': 1,
 '1489': 1,
 '637': 1,
 '2267': 1,
 '1621': 1,
 '927': 1,
 '956': 1,
 '1491': 1,
 '1044': 1,
 '1772': 1,
 '1452': 1,
 '351': 1,
 '1185': 1,
 '1392': 1,
 '1753': 1,
 '651': 1,
 '1192': 1,
 '1717': 1,
 '1596': 1,
 '971': 1,
 '1661': 1,
 '1057': 1,
 '1904': 1,
 '1114': 1,
 '1733': 1,
 '1023': 1,
 '1314': 1,
 '1749': 1,
 '1165': 1,
 '1640': 1,
 '1478': 1,
 '1826': 1,
 '1358': 1,
 '1575': 1,
 '1841': 1,
 '1668': 1,
 '2643': 1,
 '1257': 1,
 '922': 1,
 '908': 1,
 '1371': 1,
 '2617': 1,
 '968': 1,
 '1364': 1,
 '905': 1,
 '1556': 1,
 '2491': 1,
 '1197': 1,
 '1430': 1,
 '1116': 1,
 '1513': 1,
 '954': 1,
 '1875': 1,
 '2704': 1,
 '1270': 1,
 '1394': 1,
 '945': 1,
 '1454': 1,
 '1312': 1,
 '1642': 1,
 '1461': 1,
 '1524': 1,
 '1497': 1,
 '1203': 1,
 '1391': 1,
 '1140': 1,
 '896': 1,
 '2629': 1,
 '1343': 1,
 '1128': 1,
 '1644': 1,
 '980': 1,
 '348': 4,
 '1012': 1,
 '1729': 1,
 '1162': 1,
 '1700': 1,
 '1374': 1,
 '1647': 1,
 '1239': 1,
 '1619': 1,
 '1613': 1,
 '1599': 1,
 '931': 1,
 '1025': 1,
 '1540': 1,
 '1559': 1,
 '1078': 1,
 '1055': 1,
 '1646': 1,
 '1743': 1,
 '1282': 1,
 '1028': 1,
 '2009': 1,
 '1713': 1,
 '1778': 1,
 '1907': 1,
 '996': 1,
 '1360': 1,
 '1892': 1,
 '1045': 1,
 '1224': 1,
 '1506': 1,
 '964': 1,
 '2203': 1,
 '1955': 1,
 '1351': 1,
 '1900': 1,
 '1335': 1,
 '2018': 1,
 '1366': 1,
 '1442': 1,
 '2543': 1,
 '1510': 1,
 '1372': 1,
 '1402': 1,
 '1625': 1,
 '1906': 1,
 '1794': 1,
 '1895': 1,
 '1838': 1,
 '1464': 1,
 '1515': 1,
 '483': 1,
 '1180': 1,
 '1606': 1,
 '2635': 1,
 '1832': 1,
 '1035': 1,
 '1693': 1,
 '1706': 1,
 '1381': 1,
 '1248': 1,
 '1803': 1,
 '1134': 1,
 '1845': 1,
 '1087': 1,
 '1493': 1,
 '960': 1,
 '363': 1,
 '1564': 1,
 '1254': 1,
 '1310': 1,
 '1160': 1,
 '1411': 1,
 '2336': 1,
 '1505': 1,
 '1015': 1,
 '2038': 1,
 '1926': 1,
 '1632': 1,
 '1705': 1,
 '1783': 1,
 '1560': 1,
 '997': 1,
 '1863': 1,
 '1523': 1,
 '1406': 1,
 '984': 1,
 '1356': 1,
 '899': 1,
 '1194': 1,
 '1951': 1,
 '1868': 1,
 '1703': 1,
 '1622': 1,
 '1291': 1,
 '1471': 1,
 '1902': 1,
 '925': 1,
 '1034': 1,
 '909': 1,
 '2284': 1,
 '1178': 1,
 '966': 1,
 '930': 1,
 '1336': 1,
 '1159': 1,
 '2199': 1,
 '1443': 1,
 '1819': 1,
 '1347': 1,
 '1029': 1,
 '1181': 1,
 '1876': 1,
 '1569': 1,
 '1759': 1,
 '924': 1,
 '1623': 1,
 '1680': 1,
 '1816': 1,
 '1667': 1,
 '1302': 1,
 '1153': 1,
 '2636': 1,
 '1323': 1,
 '1541': 1,
 '1419': 1,
 '1840': 1,
 '1036': 1,
 '986': 1,
 '3173': 1,
 '1216': 1,
 '1005': 1,
 '1387': 2,
 '1846': 1,
 '1137': 1,
 '1612': 1,
 '937': 1,
 '1702': 1,
 '1346': 1,
 '1679': 1,
 '1659': 1,
 '1146': 1,
 '1530': 1,
 '1292': 1,
 '1883': 1,
 '1052': 1,
 '974': 1,
 '1791': 1,
 '1827': 1,
 '1628': 1,
 '1761': 1,
 '389': 1,
 '1673': 1,
 '2071': 1,
 '1773': 1,
 '1629': 1,
 '1231': 1,
 '1740': 1,
 '1458': 1,
 '1784': 1,
 '1170': 1,
 '1389': 1,
 '2445': 1,
 '2459': 1,
 '1317': 1,
 '2447': 1,
 '1117': 1,
 '1319': 1,
 '957': 1,
 '1627': 1,
 '1151': 1,
 '1307': 1,
 '1804': 1,
 '1148': 1,
 '2187': 1,
 '2508': 1,
 '1050': 1,
 '1665': 1,
 '1278': 1,
 '2001': 1,
 '975': 1,
 '1001': 1,
 '934': 1,
 '1467': 1,
 '1105': 1,
 '1488': 1,
 '1589': 1,
 '1748': 1,
 '1614': 1,
 '1648': 1,
 '1873': 1,
 '1083': 1,
 '2102': 1,
 '1720': 1,
 '1407': 1,
 '1516': 1,
 '1308': 1,
 '1409': 1,
 '1074': 1,
 '1175': 1,
 '1455': 1,
 '1227': 1,
 '1745': 1,
 '1549': 2,
 '366': 1,
 '1095': 1,
 '1103': 1,
 '1781': 1,
 '1075': 1,
 '1898': 1,
 '1021': 1,
 '1877': 1,
 '1577': 1,
 '1434': 1,
 '1322': 1,
 '1553': 1,
 '1600': 1,
 '1480': 1,
 '1672': 1,
 '1669': 1,
 '1856': 1,
 '933': 1,
 '1744': 1,
 '1636': 1,
 '1341': 1,
 '1752': 1,
 '916': 1,
 '1470': 1,
 '1796': 1,
 '1554': 1,
 '2327': 1,
 '353': 1,
 '1026': 1,
 '1373': 1,
 '1686': 1,
 '1547': 1,
 '1379': 1,
 '1459': 1,
 '1403': 1,
 '1143': 1,
 '1433': 1,
 '2740': 1,
 '1758': 1,
 '1854': 1,
 '1897': 1,
 '1727': 1,
 '1281': 1,
 '2529': 1,
 '1905': 1,
 '501': 1,
 '2180': 1,
 '1303': 1,
 '1635': 1,
 '1063': 1,
 '1003': 1,
 '1546': 1,
 '1742': 1,
 '1241': 1,
 '1290': 1,
 '1106': 1,
 '1091': 1,
 '1822': 1,
 '1512': 1,
 '1701': 1,
 '1850': 1,
 '580': 1,
 '1588': 1,
 '1741': 1,
 '1548': 1,
 '1801': 1,
 '1352': 1,
 '1212': 1,
 '1653': 1,
 '420': 1,
 '1277': 1,
 '949': 1,
 '1213': 1,
 '1449': 1,
 '1093': 1,
 '2885': 2,
 '1694': 1,
 '2116': 1,
 '1908': 1,
 '1591': 1,
 '1725': 1,
 '1426': 1,
 '1284': 1,
 '1860': 1,
 '1152': 1,
 '1525': 1,
 '1238': 1,
 '1889': 1,
 '1604': 1,
 '563': 1,
 '1551': 1,
 '1704': 1,
 '1235': 1,
 '1864': 1,
 '1708': 1,
 '1139': 1,
 '1098': 1,
 '2337': 1,
 '1511': 1,
 '1058': 1,
 '1833': 1,
 '942': 1,
 '1592': 1,
 '1047': 1,
 '995': 1,
 '901': 1,
 '950': 1,
 '1316': 1,
 '1707': 1,
 '1207': 1,
 '1032': 1,
 '1186': 1,
 '1174': 1,
 '1293': 1,
 '1807': 1,
 '1626': 1,
 '1466': 1,
 '987': 1,
 '921': 1,
 '1062': 1,
 '1311': 1,
 '1131': 1,
 '1504': 1,
 '1874': 1,
 '1519': 1,
 '1698': 1,
 '1418': 1,
 '2838': 2,
 '1764': 1,
 '2183': 1,
 '963': 1,
 '1306': 1,
 '1414': 1,
 '1503': 1,
 '1884': 1,
 '1250': 1,
 '1286': 1,
 '1624': 1,
 '910': 1,
 '1558': 1,
 '2283': 1,
 '1657': 1,
 '1264': 1,
 '1208': 1,
 '1563': 1,
 '1518': 1,
 '1124': 1,
 '2133': 1,
 '1543': 1,
 '1273': 1,
 '1090': 1,
 '1583': 1,
 '946': 1,
 '1234': 1,
 '1183': 1,
 '1557': 1,
 '1112': 1,
 '1061': 1,
 '1121': 1,
 '1654': 1,
 '1141': 1,
 '1040': 1,
 '1132': 1,
 '2319': 1,
 '1295': 1,
 '549': 2,
 '928': 1,
 '1211': 1,
 '1206': 1,
 '1147': 1,
 '1133': 1,
 '1275': 1,
 '1200': 1,
 '907': 1,
 '2171': 1,
 '1886': 1,
 '1102': 1,
 '1509': 1,
 '1274': 1,
 '1834': 1,
 '1218': 1,
 '1479': 1,
 '1210': 1,
 '972': 1,
 '1813': 1,
 '1168': 1,
 '1769': 1,
 '1370': 1,
 '2068': 1,
 '1469': 1,
 '1574': 1,
 '1017': 1,
 '2458': 1,
 '1097': 1,
 '1865': 1,
 '1731': 1,
 '1594': 1,
 '1173': 1,
 '2384': 1,
 '1445': 1,
 '1435': 1,
 '2398': 1,
 '970': 1,
 '1481': 1,
 '1142': 1,
 '1800': 1,
 '912': 1,
 '1690': 1,
 '1130': 1,
 '941': 1,
 '1441': 1,
 '1377': 1,
 '1199': 1,
 '1750': 1,
 '1724': 1,
 '1806': 1,
 '1088': 1,
 ...}

Furthermore, given this mapping of people to friendship scores, we will want to sort the potential friends from best to worst before presenting it to the user.


In [25]:
def number_dict_to_sorted_list(dic):
    """Given a dict whose values are numbers, return a list of the keys.
    The keys are sorted by the number they map to, from greatest to least.
    When two keys map to the same number, the keys are sorted by their
    natural sort order, from least to greatest."""
    return ...
    
number_dict_to_sorted_list({'A': 1, 'B': 3, 'C': 1})


Out[25]:
['B', 'C', 'A']

Finally, the function that provides with the recommendations for an user.


In [26]:
def recommend_by_number_of_common_friends(graph, user):
    """Return a list of friend recommendations for the given user.
    The friend recommendation list consists of names of people in the graph
    who are not yet a friend of the given user.
    The order of the list is determined by the number of common friends.
    """
    return ...

recommend_by_number_of_common_friends(facebook, "0")[:10]


Out[26]:
['348', '1684', '414', '1486', '1912', '3003', '1297', '428', '1193', '1718']

Conclusions

Write your own conclusions!


*[Nathan Fillion's Bacon number is...](https://www.google.ca/search?q=nathan+fillion+bacon+number)*