<jupyter_start><jupyter_text>CS446/546 - Class Session 3 - Degree DistributionIn this class session we are going to plot the degree distribution of the undirected humanprotein-protein interaction network (PPI), without using `igraph`. We'll obtain the interaction data from the Pathway Commons SIF file (in the `shared/` folder) and we'll manually compute the degree of each vertex (protein) in the network. We'll then computethe count `N(k)` of vertices that have a given vertex degree `k`, for all `k` values.Finally, we'll plot the degree distribution and discuss whether it is consistent with the results obtained in the Jeong et al. article for the yeast PPI.   We'll start by loading all of the Python modules that we will need for this notebook.  Because we'll be calling a bunch of functions from `numpy` and `matplotlib.pyplot`, we'll alias them as `np` and `plt`, respectively.<jupyter_code>import pandas
import collections
import matplotlib.pyplot as plt
import numpy as np
import scipy.stats
import igraph<jupyter_output><empty_output><jupyter_text>Step 1:  load in the SIF file as a `pandas` data frame using `pandas.read_csv`.  Make sure the column names of your data frame are `species1`, `interaction_type`, and `species2`. Save the data frame as the object `sif_data`.<jupyter_code>sif_data =<jupyter_output><empty_output><jupyter_text>Step 2:  restrict the interactions to protein-protein undirected ("in-complex-with", "interacts-with"). The restricted data frame should be called `interac_ppi`. Then we will make a copy using `copy` so `interac_ppi` is independent of `sif_data` which will be convenient for this exercise.<jupyter_code>interaction_types_ppi = 
interac_ppi =<jupyter_output><empty_output><jupyter_text>Step 3: for each interaction, reorder `species1` and `species2` (if necessary) so that`species1  species1` (by lexicographic order) for that row, or `False` otherwise.  You can then use the `loc` method on the data frame, to select rows based on `boolean_vec` and the two columns that you want (`species1` and `species2`). Thanks to <NAME> for suggesting this approach (which is more elegant than looping over all rows):<jupyter_code>boolean_vec = 
interac_ppi.loc[boolean_vec, ['species1', 'species2']] =<jupyter_output><empty_output><jupyter_text>Since iterating is reasonably fast in Python, you could also do this using a `for` loop through all of the rows of the data frame, swapping `species1` and `species2` entries as needed (and in-place in the data frame) so that in the resulting data frame `interac_ppi` satisfies `species1 < species2` for all rows.<jupyter_code>for rowid, row in interac_ppi.head().iterrows():
    if row['species1'] > row['species2']:
        interac_ppi['species1'][rowid] = 
        interac_ppi['species2'][rowid] =<jupyter_output><empty_output><jupyter_text>Step 4: Restrict the data frame to only the columns `species1` and `species2`. Use the `drop_duplicates` method to subset the rows of the resulting two-column data frame to only unique rows. Assign the resulting data frame object to have the name `interac_ppi_unique`.  This is basically selecting only unique pairs of proteins, regardless of interaction type.<jupyter_code>interac_ppi_unique =<jupyter_output><empty_output><jupyter_text>Step 5: compute the degree of each vertex (though we will not associate the vertex degrees with vertex names here, since for this exercise we only need the vector of vertex degree values, not the associated vertex IDs).  You'll want to create an object called `vertex_degrees_ctr` which is of class `collections.Counter`.  You'll want to name the final list of vertex degrees, `vertex_degrees`.<jupyter_code>allproteins = 
vertex_degrees_ctr =
vertex_degrees =<jupyter_output><empty_output><jupyter_text>Let's print out the vertex degrees of the first 10 vertices, in whatever the key order is. Pythonistas -- anyone know of a less convoluted way to do this? Let's print out the first ten entries of the `vertex_degrees` list.  Note that we don't expect it to be in the same order as the output from the previous command above, since `dict` changes the order in the above. Step 6: Calculate the histogram of N(k) vs. k, using 30 bins, using `plt.hist`.  You'll probably want to start by making a `numpy.array` from your `vertex_degrees`.  Call the resulting object from `plt.hist`, `hist_res`. Obtain a numpy array of the bin counts as element zero from `hist_res` (name this object `hist_counts`) and obtain a numpy array of the bin centers (which are `k` values) as element one from `hist_res` (name this object `hist_breaks`). Finally, you want the `k` values of the centers of the bins, not the breakpoint values. So you'll have to do some arithmetic to go from the 31 `k` values of the bin breakpoints, to a numpy array of the 30 `k` values of the centers of the bins.  You should call that object `kvals`.<jupyter_code>nbins =
hist_res =
hist_counts = 
hist_breaks = 
kvals =<jupyter_output><empty_output><jupyter_text>Let's print the k values of the bin centers:<jupyter_code>kvals<jupyter_output><empty_output><jupyter_text>Let's print the histogram bin counts:<jupyter_code>hist_counts<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.07550077041602465, 'fraction_numerical': 0.007896764252696456, 'mean_word_length': 5.507518796992481, 'pattern_counts': {'":': 0, '<': 43, '<?xml version=': 0, '>': 43, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, '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': '10', 'dir': 'jupyter-structured-clean-dedup', 'id': '440927', 'license': 'Apache-2.0', 'n_tokens_mistral': 1573, 'n_tokens_neox': 1499, 'n_words': 685, 'path': 'class03_degdist_python3_template.ipynb', 'repo_name': 'curiositymap/Networks-in-Computational-Biology', 'size': '5199'}