<jupyter_start><jupyter_text>Practice Session 06: PageRank We will compute PageRank on a graph that represents the web of UK around 2007. Each node is a host, and there is a link between two hosts if there is a web page in one of them pointing to a web page in the other one. This network is weighted: the weight is the number of pages that point from one host to the other one.The collection we will use, [WEBSPAM-UK2007](http://chato.cl/webspam/datasets/uk2007/), has been used in multiple studies on the effect of web spam. Feel free to decompress these files to inspect them, **but your code must read only these files in compressed form**:* ``webspam_uk2007-nodes.csv.gz`` contains (``nodeid``, ``hostname``, ``label``) records* ``webspam_uk2007-edges.csv.gz`` contains (``source``, ``destination``, ``weight``) recordsYour task is to compute PageRank twice: first considering all the links, and then ignoring links from or to a known spam host.(Remove this cell when delivering.)  0. Code snippets you may need 0.1. Read a CSV file with a headerSuppose ``FILENAME`` points to a file with the following contents:```a,b,c,d1,2,3,45,6,7,8```The following code:```pythonwith gzip.open(FILENAME, "rt", encoding="utf-8") as input_file:    reader = csv.DictReader(input_file, delimiter=',', quotechar='"')    for record in reader:        print(record["b"])```Prints:```26``` 0.2. Sort a list of scoresYou can use the `enumerate()` function which converts a list `[a, b, c]` into `[(0,a), (1,b), (2,c)]` and then `sort()` as follows. Suppose ``score`` contains ``[0.2, 0.7, 0.4]``:```pythonhosts_by_score = sorted(enumerate(score), key=lambda x: x[1], reverse=True)```Will return the list `[(1,0.7), (2,0.4), (0,0.2)]`(Remove this cell when delivering.)  1. Read host names Read the names of the nodes into a dictionary `id2name`, and the labels into another dictionary `id2label`. They keys (nodeids) should be converted to integers using ``int(...)``. Remember in this file each record contains ``nodeid``, ``hostname``, and ``label``.(Remove this cell when delivering.)<jupyter_code>import io
import gzip
import csv
INPUT_NODES_FILENAME = "webspam_uk2007-nodes.csv.gz"
INPUT_EDGES_FILENAME = "webspam_uk2007-edges.csv.gz"<jupyter_output><empty_output><jupyter_text>Replace this cell with your code to read the nodes file into id2name and id2label. Verify that you are reading correctly the file:    ```pythonprint("%s: %s" % (id2name[873], id2label[873]))print("%s: %s" % (id2name[105715], id2label[105715]))print("Number of hosts: %s" % len(id2name))```Should print:```bbc.co.uk: nonspamwww.top-mobile-phones.co.uk: spamNumber of hosts: 114529```If you get a key not found error, most likely you did not convert the ids to integers.(Remove this cell when delivering.) Count how many hosts are labeled as spam, how many as nonspam, and how many are unlabeled, which should be the majority.(Remove this cell when delivering.) Replace this cell with your code to print how many hosts are spam, how many are nonspam, and how many are unlabeled (this should be the large majority).  2. Compute the degree of each node Compute the out-degree of each node and store it in the dictionary id2degree. For this, you will need to read the edges file once. This file contains (``source``, ``destination``, ``weight``) records(Remove this cell when delivering.)<jupyter_code># Initialization of id2degree

id2degree = {}
N = len(id2name)
for nodeid in range(N):
    id2degree[nodeid] = 0<jupyter_output><empty_output><jupyter_text>Replace this cell with your code to read the degrees of nodes into id2degree. Verify that you are reading correctly the file:    ```pythonprint("%s: %s" % (id2name[890], id2degree[890]))print("%s: %s" % (id2name[1469], id2degree[1469]))print("%s: %s" % (id2name[105715], id2degree[105715]))```Should print:```bc1.org.uk: 16candycaine.skinthesun.co.uk: 22www.top-mobile-phones.co.uk: 0```If you get a key not found error, most likely you did not convert the ids to integers or you did ot initialize the id2degree.(Remove this cell when delivering.)  3. Compute PageRank Perform `iterations=20` iterations with `alpha=0.85`. In each iteration, you will read the file of the graph, **without loading the entire graph in memory**. This means each iteration involves opening (and implicitly, closing) the edges file.Your code should do the following:* At the beginning, initialize the vector `pagerank` as a vector of 1/N and the vector `pagerank_aux` as a vector of 0s.* For `iterations` iterations:   * Read the graph and for every link from *source* to *destination*:      * Add to `pagerank_aux[destination]` the value `pagerank[source]/degree`, where *degree* is the out-degree of the source node (i.e, its number of out-links).   * Set *pagerank* of every node to *alpha x pagerank_aux + (1.0-alpha) x (1.0/N)*.   * Set `pagerank_aux` to 0.0Remember: do not keep the graph in memory, because that will limit the size of the graphs your code can handle. At every iteration you must read the file again.(Remove this cell when delivering.)<jupyter_code>ITERATIONS = 20
ALPHA = 0.85<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.11661466458658347, 'fraction_numerical': 0.03217628705148206, 'mean_word_length': 5.164663461538462, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 13, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '3', 'dir': 'jupyter-structured-clean-dedup', 'id': '346778', 'license': 'CC-BY-4.0', 'n_tokens_mistral': 1644, 'n_tokens_neox': 1527, 'n_words': 669, 'path': 'practicum/OLD-ps06_pagerank.ipynb', 'repo_name': 'MarziKarimi/networks-science-course', 'size': '5128'}