#!/usr/bin/env python
# coding: utf-8
# # Capability Correlations
# Let's start by importing all of the necessary libraries to conduct the analysis.
# In[1]:
from py2neo import Graph
import numpy as np
from pandas import DataFrame
import itertools
import matplotlib.pyplot as plt
import seaborn as sns
import json
import math
import pandas as pd
import plotly
import plotly.graph_objs as go
import qgrid
from scipy import stats, spatial
from sklearn.cluster.bicluster import SpectralBiclustering
import operator
from IPython.display import display, HTML
from matplotlib.colors import ListedColormap
from wordcloud import WordCloud
# please add your plotly api credentials to plotly_config in your own machine. Visit https://plot.ly/python/getting-started/
plotly_config = json.load(open('plotly_config.json'))
plotly.tools.set_credentials_file(username=plotly_config['username'], api_key=plotly_config['key'])
# ### Table of Contents:
# - [1. Database Matrix of Occurences](#one)
# - [1.1. Getting the data from Neo4j](#one-one)
# - [1.2. Designing the queries](#one-two)
# - [1.3. The first part of the matrix: No intersections.](#one-three)
# - [1.4. The second part of the matrix: Intersections.](#one-four)
# - [1.5. Testing the co-occurence matrix](#one-five)
# - [1.6. Printing the matrix](#one-six)
# - [2. Co-occurence by country](#two)
# - [2.1. Co-ocurence matrixes for countries](#two-one)
# - [2.2. Transforming the co-occurence matrix into a list](#two-two)
# - [2.3. Visualizing correlations](#two-three)
# - [2.4. Creating a correlation matrix](#two-four)
# - [2.4.1. Regular Matrix](#two-four-one)
# - [2.4.2. Reordered Matrix: Clustermap](#two-four-two)
# - [2.5. Country profiles](#two-five)
# - [3. Contextual Relations](#three)
# - [3.1. GDP per capita](#three-one)
# - [3.1.1. GDP per capita and capabilities](#three-one-one)
# - [3.1.2. Country Profiles and Correlation: Denmark](#three-one-two)
# - [3.1.3. Country Profiles and Correlation: Other countries](#three-one-three)
# - [3.1.4. Utilizing the average GDP per capita](#three-one-four)
# - [3.2. Collaborations](#three-two)
# - [3.2.1. Collaboration Matrix](#three-two-one)
# - [3.2.2. Collaborations and Capabilities](#three-two-two)
# - [3.2.3. Normalized Collaborations and Capabilities](#three-two-three)
# - [4. The case of Denmark](#four)
# - [4.1. Visualizing Differences](#four-one)
# - [4.2. Understanding Differences](#four-two)
# - [4.3. Country Spectrums Revisited](#four-three)
# - [4.3.1. Country Spectrums: Zooming In](#four-three-one)
# - [4.3.2. Country Spectrums: Limited Countries](#four-three-two)
# - [4.3.3. Country Spectrums: Full Representation](#four-three-three)
# - [4.3.4. Country Spectrums: Pairs with more than X occurency](#four-three-four)
# - [4.3.5. Country Spectrums: Diving into pairs](#four-three-five)
# ## 1. Database Matrix of Occurences
# In order to establish a base for understading the basis of the work, we wish to understand the occurence of severall feedstocks, processing technologies and outputs in our database.
#
# For example, how many assets (patents, papers, etc) contain the mix of processing technology X for output Y?
#
# To understand this in a more general way, the [AMICA](https://amica-pathfinder.net/) database will be transformed in an [co-occurence matrix](https://en.wikipedia.org/wiki/Co-occurrence_matrix). This means, in the above described example that the number of assets that contain that mix will be an entry in a matrix, whyle the corresponfing technology and output will be columns/lines of the matrix.
# ### 1.1. Getting the data from Neo4j
# The first step in the analysis is to get the data from the [AMICA](https://amica-pathfinder.net/) database. This data is stored in a graph database of the type [Neo4j](https://neo4j.com/).
# We use [py2neo](http://py2neo.org/v3/) to establish a connection to the neo4j database.
# In[2]:
local_connection_url = "http://localhost:7474/db/data"
connection_to_graph = Graph(local_connection_url)
# ### 1.2. Designing the queries
# Two queries to the database were designed, the first, only related to non intersecting data, this means, looking for co-occurences of:
# - outputs and technologies that appear together in an asset.
# - technologies and feedstocks that appear together in an asset.
# - feedstocks and outputs that appear together in an asset.
# In[3]:
query_no_interestions = """ MATCH (a:Asset)-[:CONTAINS]->(fs:Feedstock)
MATCH (a:Asset)-[:CONTAINS]->(out:Output)
MATCH (a:Asset)-[:CONTAINS]->(pt:ProcessingTech)
RETURN fs.term, pt.term, out.term, count(a)
"""
# The second query is designed to also fetch the intersections between different outputs, different processing technologies and different feedstocks. This relates to:
# - outputs that appear together in the same asset.
# - technologies that appear together in the same asset.
# - outputs that appear together in the same asset.
# In[4]:
# issue: this query needs to be divided by two when building the matrix -> NON OPTIMIZED
process_variables = ['Feedstock', 'Output', 'ProcessingTech']
query_intersections = """ MATCH (a:Asset)-[:CONTAINS]->(fs:{})
MATCH (a:Asset)-[:CONTAINS]->(t:{})
WHERE fs<>t
RETURN fs.term, t.term, count(a)
"""
# ### 1.3. The first part of the matrix: No intersections.
# In order to get the axis of our co-occurence matrix we make all the necessary queries and gather all the names that appear in a `matrix_axis_names` list.
# In[5]:
# Return query as pandas dataframe
data_no_intersections = DataFrame(connection_to_graph.data(query_no_interestions)).as_matrix()
# Get axis names from columns and append to list
feedstock_names = set(list(data_no_intersections[:, 1]))
processing_technology_names = set(list(data_no_intersections[:, 2]))
output_names = set(list(data_no_intersections[:, 3]))
matrix_axis_names = list(feedstock_names) + list(processing_technology_names) + list(output_names)
# Extra labels that only appear in non-intersection queries
for category in process_variables:
data_no_intersections = DataFrame(connection_to_graph.data(query_intersections.format(category, category))).as_matrix()
for column_number in range(1,3):
column = data_no_intersections[:, column_number]
for name in column:
if name not in matrix_axis_names:
matrix_axis_names.append(name)
# The co-occurence matrix will be called `matrix`. In order to get things started we need two things:
#
# - An empty matrix with the shape of the previously built axis:
# In[6]:
matrix = np.zeros([len(matrix_axis_names), len(matrix_axis_names)])
# - A function that given a certain name, returns the position of that name in a list:
# In[7]:
def find_index(something, in_list):
return in_list.index(something)
# Finally, we can start building the first part of the matrix. To do so, we iterated over all of the rows of the data retreived in the `data_no_intersections` table.
# In[8]:
# for every row in original response
for row in data_no_intersections:
# the last column is the frequency
frequency = row[0]
indexes = [find_index(element, matrix_axis_names) for element in row[1::]]
# add frequency value to matrix position
for pair in itertools.combinations(indexes, 2):
matrix[pair[0], pair[1]] += frequency
matrix[pair[1], pair[0]] += frequency
# ### 1.4. The second part of the matrix: Intersections.
# The second part of the matrix that should be built related to the second query. Intersecting categories.
# In[9]:
# for every type of asset
for category in process_variables:
print 'Processing ', category
# execute the query
process_data = DataFrame(connection_to_graph.data(query_intersections.format(category, category))).as_matrix()
# fill the matrix
for row in process_data:
frequency = row[0]
indexes = [find_index(element, matrix_axis_names) for element in row[1::]]
# add frequency value to matrix position
for pair in itertools.combinations(indexes, 2):
matrix[pair[0], pair[1]] += frequency / 2 # Divided by two because query not optimized
matrix[pair[1], pair[0]] += frequency / 2 # Divided by two because query not optimized
# ### 1.5. Testing the co-occurence matrix
# Some basic statistics about the co-occurence matrix.
# In[10]:
print 'Rows:', matrix.shape[0]
print 'Columns:', matrix.shape[1]
print 'Mean: ', np.mean(matrix)
print 'Standart Deviation', np.std(matrix)
print 'Max: ', np.amax(matrix)
print 'Min: ', np.amin(matrix)
# After testing, we normalize the matrix.
# In[11]:
normalized_matrix = (matrix - np.mean(matrix)) / np.std(matrix)
# Symmetricality verification of normalized and non-normlized co-occurence matrixes.
# In[12]:
def check_symmetric(a, tol):
return np.allclose(a, a.T, atol=tol)
print 'The non normalized matrix is symmetrical: {}'.format(check_symmetric(matrix, 1e-8))
print 'The normalized matrix is symmetrical: {}'.format(check_symmetric(normalized_matrix, 1e-8))
# The following cell will verify if there is a non-zero element in the diagonal of the matrix.
# In[13]:
for column_number in range(matrix.shape[0]):
if matrix[column_number, column_number] != 0:
print 'Non-zero entry found in entry {}'.format(column_number)
# ### 1.6. Printing the matrix
# In[14]:
# create subplots
plt.subplots(2,1,figsize=(17,17))
plt.subplot(121)
sns.heatmap(matrix, cmap='BuPu_r', cbar=None, square=True, xticklabels=False, yticklabels=False)
plt.title('Co-occurence matrix heatmap: Non-normalized')
plt.subplot(122)
sns.heatmap(normalized_matrix, cmap='BuPu_r', cbar=None, square=True, xticklabels=False, yticklabels=False)
plt.title('Co-occurence matrix heatmap: Normalized')
plt.show()
# ## 2. Co-occurences and countries
# In this part of the analysis, severall co-occurence matrixes will be produced. Ideally, one for every country in the database.
# ### 2.1. Co-ocurence matrixes for countries
# We start by getting a list of all of the countries in the neo4j database.
# In[15]:
country_query = """ MATCH (n:Country)
WITH n.name AS Country
RETURN Country;
"""
country_names = list(set(DataFrame(connection_to_graph.data(country_query)).as_matrix()[:, 0]))
country_names.sort()
print 'The country list has {} countries.'.format(len(country_names))
# After doing this, we prepare a function that given a certain country, will retrieve the co-occurence matrix. This process is similar to the process in "[1.3. The first part of the matrix: No intersections](#one-three)" but applied to a particular country. By aggregating the process done before in a single function.
# In[16]:
def get_country_matrix(country, normalization=True):
# define queries
country_no_interestions = """ MATCH (a:Asset)-[:CONTAINS]->(fs:Feedstock)
MATCH (a:Asset)-[:CONTAINS]->(out:Output)
MATCH (a:Asset)-[:CONTAINS]->(pt:ProcessingTech)
WHERE a.country = "{}"
RETURN fs.term, pt.term, out.term, count(a)
""".format(country)
process_variables = ['Feedstock', 'Output', 'ProcessingTech']
country_intersections = """ MATCH (a:Asset)-[:CONTAINS]->(fs:{})
MATCH (a:Asset)-[:CONTAINS]->(t:{})
WHERE fs<>t AND a.country = "{}"
RETURN fs.term, t.term, count(a)
"""
# get data
data_no_intersections = DataFrame(connection_to_graph.data(country_no_interestions)).as_matrix()
# create matrix
country_matrix = np.zeros([len(matrix_axis_names), len(matrix_axis_names)])
# for no intersections data
for row in data_no_intersections:
# the last column is the frequency (count)
frequency = row[0]
indexes = [find_index(element, matrix_axis_names) for element in row[1::]]
# add frequency value to matrix position
for pair in itertools.combinations(indexes, 2):
country_matrix[pair[0], pair[1]] += frequency
country_matrix[pair[1], pair[0]] += frequency
# for intersecting data
for category in process_variables:
process_data = DataFrame(connection_to_graph.data(country_intersections.format(category, category, country))).as_matrix()
for row in process_data:
frequency = row[0]
indexes = [find_index(element, matrix_axis_names) for element in row[1::]]
# add frequency value to matrix position
for pair in itertools.combinations(indexes, 2):
country_matrix[pair[0], pair[1]] += frequency / 2 # Divided by two because query not optimized
country_matrix[pair[1], pair[0]] += frequency / 2 # Divided by two because query not optimized
# normalize
#normalized_country_matrix = (country_matrix - np.mean(country_matrix)) / np.std(country_matrix)
no_duplicates = np.triu(country_matrix, 1)
total_documents = np.sum(no_duplicates)
normalized_country_matrix = country_matrix / total_documents
# dynamic return
if normalization == True:
return normalized_country_matrix
else:
return country_matrix
# Let's create a function that returns basic stats given a matrix. With this function, we can gain insight into the previous function.
# In[17]:
def basic_stats(a_matrix):
print 'Rows:', a_matrix.shape[0]
print 'Columns:', a_matrix.shape[1]
print 'Mean: ', np.mean(a_matrix)
print 'Standart Deviation', np.std(a_matrix)
print 'Max: ', np.amax(a_matrix)
print 'Min: ', np.amin(a_matrix)
print 'Symmetry: ', check_symmetric(matrix, 1e-8)
print ''
# Let's test a couple of countries. By getting their co-occurence matrix and printing its properties.
# In[18]:
print 'Denmark co-occurence matrix stats:'
basic_stats(get_country_matrix('Denmark', normalization=True))
print 'Sweden co-occurence matrix stats:'
basic_stats(get_country_matrix('Sweden', normalization=True))
# In[19]:
# create subplots
plt.subplots(2,1,figsize=(17,17))
plt.subplot(121)
sns.heatmap(get_country_matrix('Denmark', normalization=True), cmap='BuPu_r', cbar=None, square=True, xticklabels=False, yticklabels=False)
plt.title('Normalized Capability Matrix: Denmark')
plt.subplot(122)
sns.heatmap(get_country_matrix('Sweden', normalization=True), cmap='BuPu_r', cbar=None, square=True, xticklabels=False, yticklabels=False)
plt.title('Normalized Capability Matrix: Sweden')
plt.show()
# ### 2.2. Transforming the co-occurence matrix into a list
# One of the goals of the analysis is to understand how each country relates to another. To do this, we will need to transform the matrix of a given country into an array.
#
# After doing this we will be able to compare the array of each one of the countries, by computing their difference or correlation for example.
# Let's start by creating a function that given a symetric matrix, as the ones shown above, returns a list. This list will have an entry by position in the matrix. But since the matrixes are symmetrical, the list will only receive half of the matrix.
#
# This means that for a matrix of dimensions 342x342 the list will have a total of 58 482 entries.
# In[20]:
def get_list_from(matrix):
total_rows = matrix.shape[0]
only_valuable = []
extension = 1
for row_number in range(total_rows):
only_valuable.append(matrix[row_number, extension:total_rows].tolist())
extension += 1
return [element for column in only_valuable for element in column ]
# ### 2.3. Visualizing correlations
# Let's visualize the lists produced by this workflow for two different countries.
#
# We first select two countries.
# In[21]:
spectrum_countries = ['''People's Republic of China''', 'United States of America']
# We then create a matrix where each row is the vector that describes the country's capabilities.
# In[22]:
# apply functions to both countries
country_1_list = get_list_from(get_country_matrix(spectrum_countries[0], normalization=True))
country_2_list = get_list_from(get_country_matrix(spectrum_countries[1], normalization=True))
# create a matrix where each row is a list of a country
corelation = np.vstack((country_1_list, country_2_list))
# plot the matrix
plt.subplots(1,1,figsize=(20, 5))
plt.subplot(111)
sns.heatmap(corelation, cmap='hot', cbar=None, square=False, yticklabels=[spectrum_countries[0], spectrum_countries[1]], xticklabels=False)
plt.yticks(rotation=0)
plt.title('Country Capability Spectrum', size=15)
plt.show()
# We can see that the spectrum differs significantly in some areas. Please note that all of the measure were normalized prior to the plotting.
# ### 2.4. Creating a correlation matrix
# #### 2.4.1. Regular Matrix
# In this part of the analysis we will start correlating countries in relation to their capabilities.
#
# The correlation matrix follows the following principle:
# - Entry (i, j) is the correlation index between country i and country j
# - The correlation index between country i and j is the absolute average difference between the capability list of country i and j.
# Now, taking the list of countries previously established, we can iterate through it and fill the matrix.
#
# To improve eficiency, we first create a dictionnary where each key is a country, and each value, the capability list.
#
# In the case that the databse contains no assets about a certain country, that country will be discarted.
# In[23]:
# create dictionnary
country_capability_dict = {}
counter = 0
# iterate through countries
for country in country_names:
counter += 1
country_matrix = get_country_matrix(country, normalization=True)
# discart if no information
if np.all(np.isnan(country_matrix)):
continue
else:
country_capability_dict[country] = get_list_from(country_matrix)
np.save('Data/country_capability_dict.npy', country_capability_dict)
# Let's create a function that given two countries and a method, returns a suitable correlation coeficient.
#
# Here, the code will give three possible outputs:
# - `abs_avg_dif`: the absolute average difference between two vectors.
# - `Pearson`: The [pearson](https://docs.scipy.org/doc/scipy-0.14.0/reference/generated/scipy.stats.pearsonr.html) correlation coeficient between two vectors.
# - `P-value`: The p-value according to [scipy](https://docs.scipy.org/doc/scipy-0.14.0/reference/generated/scipy.stats.pearsonr.html).
# In[24]:
def calculate_country_correlation(country1_list, country2_list, stat):
avg_dif = np.mean(country1_list - country2_list)
abs_avg_dif = abs(avg_dif)
if stat.lower() == 'absolute average difference': # return absolute average difference
return abs_avg_dif
if stat == 'Pearson': # return Pearson coef
return stats.pearsonr(country1_list, country2_list)[0]
if stat == 'P-value': # return P-value
return stats.pearsonr(country1_list, country2_list)[1]
# The matrix is built, with the following steps:
# 1. For each country, get its asset co-occurence matrix.
# 2. Normalize the matrix by subtracting the mean and dividing by the standard deviation.
# 3. Transform the matrix into a list by taking its upper triangle.
# 4. For each entry (i,j) of the matrix, calculate the correlation of the list of country i and the list of country j.
# In[25]:
country_names = country_capability_dict.keys()
country_names.sort()
number_of_countries = len(country_names)
country_correlation = np.zeros([number_of_countries, number_of_countries])
for row in range(number_of_countries):
print 'Processing country {} / {} \r'.format(row + 1, number_of_countries),
country_1 = country_names[row]
country_1_list = np.asarray(country_capability_dict[country_1])
for column in range(number_of_countries):
country_2 = country_names[column]
country_2_list = np.asarray(country_capability_dict[country_2])
country_correlation[row, column] = calculate_country_correlation(country_1_list, country_2_list, 'Pearson')
np.save('Data/country_correlation.npy', country_correlation)
np.save('Data/country_names.npy', country_names)
# In[26]:
print 'Minimum correlation value is {} for countries {} and {}.'.format(country_correlation[np.unravel_index(country_correlation.argmin(), country_correlation.shape)[0],np.unravel_index(country_correlation.argmin(), country_correlation.shape)[1]],country_names[np.unravel_index(country_correlation.argmin(), country_correlation.shape)[0]], country_names[np.unravel_index(country_correlation.argmin(), country_correlation.shape)[1]])
# After building the matrix, we create the first heatmap of that matrix using the `sns.heatmap` function.
# In[27]:
plt.subplots(1,1,figsize=(13, 13))
plt.subplot(111)
sns.heatmap(country_correlation, cbar=None, square=True, yticklabels=country_names, xticklabels=country_names)
plt.title('Country Correlation Matrix: Unordered', size=13)
plt.show()
# A couple of things worth noting in the first visualization:
# - All of the values of the heatmap are between 0 and 1.
# - A value of 1 indicates the highest level of correlation. For this reason, the diagonal has values equal to 1.(This because it corresponds to the correaltion of a country to itself.)
# - The lighter the color of the correlation, the higher the level of correlation.
# - If a cell in the heatmap is totally dark, this indicates no correlation at all.
#
# **Light Cell - High Correlation:** This indicates that the capability profile of the two countries concerned is similar. Which can be interpreted as the countries having "similar" research profiles.
#
# **Dark Cell - Low Correlation:** This indicates that the capability profile of the two countries concerned is different. Which can be interpreted as the countries having divergent research profiles.
#
# [INTERACTIVE PLOTLY VERSION.](https://plot.ly/~duarteocarmo/24)
# #### 2.4.2. Reordered Matrix: Clustermap
# In this part, we will create a clustermap of the heatmap produced in the previous sections.
#
# To do this, we use the `sns.clustermap` function (see documentation [here](http://seaborn.pydata.org/generated/seaborn.clustermap.html)) that produces two things:
# - A reordered heatmap according to 'similarity'. This method reorders the matrix using Hierarchical agglomerative clustering with single linkage (minimum distance). See more info about this algorithm [here](https://docs.scipy.org/doc/scipy/reference/generated/scipy.cluster.hierarchy.linkage.html).
# - This clustermap also creates a [dendogram](https://en.wikipedia.org/wiki/Dendrogram) of the linkages that the algorithm produces.
#
# In[28]:
# plot the clustermap
a = sns.clustermap(country_correlation, figsize=(15, 15), xticklabels = country_names, yticklabels=country_names)
np.save('Data/correlation_matrix.npy', country_correlation)
np.save('Data/correlation_matrix_names.npy', country_names)
plt.show()
# Some interesting observations and hypothesis:
# - **Language matters:** UK and USA, for example, are highly correlated. (68% correlation)
# - **Distance matters: ** Costa-Rica and Guatemala have a correlation of 71%.
# - **Other Factors might matter: **: Portugal and Denmark for example, have a correlation of 61%.
#
#
# *PS: the percentage of correlation is achieved by multiplying the Pearson correlation index by 100.*
# ### 2.5. Country profiles
# Another interesting analysis is understanding how one country relates to other countries itself. This is done by *slicing* the heatmap produced in the previous section.
#
# By producing a bar plot for every country we can see how it relates to others and possibly find meaningful patterns.
#
# Let's start by selecting a couple of countries:
# In[29]:
countries = ['Denmark', 'United Kingdom']
# After selecting countries, we can now plot two different profiles.
# In[30]:
# for each country selected
for country in countries:
# find the matrix slice
country_index = find_index(country, country_names)
histogram_data = country_correlation[:, country_index]
# remove the country itself from data and labels
histogram_data = np.delete(histogram_data, country_index)
clean_country_names = np.delete(country_names, country_index)
# sort labels and data
sorted_names = [name for _,name in sorted(zip(histogram_data, clean_country_names))]
histogram_data.sort()
#plot
plt.subplots(1,1,figsize=(15,7))
sns.barplot(np.arange(len(histogram_data)), histogram_data * 100)
plt.xticks(np.arange(len(histogram_data)), sorted_names, rotation=90, fontsize=11)
plt.title('Country Profile: {}'.format(country))
plt.ylabel('Correlation Percentage')
plt.show()
# [INTERACTIVE PLOTLY VERSION](https://plot.ly/~duarteocarmo/26)
#
# Some important information comes from these profiles:
# - Using these profile we can dive deeper into each country to confirm the above hypothesis.
# - Looking at UK's profile, the top three countries with highest correlation with it are: USA, China and India. This can mean that language is a very important factor for correlation but also eceonomic development for example.
# - Looking at Denmark's profile, the 3 most similar countries are: Spain, Portugal and China. This indicates that there is possibly another important factor at play.
# ## 3. Contextual Relations (WIP)
# We will now study the relationship between the previously found correlations and other characteristics.
# ### 3.1. GDP per capita
#
# Let us investigate how the GDP per capita is related to the country capabilities.
#
# The world bank has data available on the GDP per capita for (almost) every country in the world.
#
# [Source](https://data.worldbank.org/indicator/NY.GDP.PCAP.CD)
# Let us investigate what countries or elements are not available in the World Bank database:
# In[31]:
data = pd.read_csv('Data/GDP_per_capita.csv', delimiter=';', header=None).as_matrix()
print 'Countries that do not have data:'
for country in country_names:
if country not in data[:, 0]:
print country
# #### 3.1.1. GDP per capita and capabilities
# We delete these entries from the `country_correlation` matrix (our heatmap) and create an `adapted_country_correlation` that is equal, without the entries that do not have GDP data available.
# In[32]:
countries_not_available = ['Asia', 'Null', 'Korea']
index_countries_not_available = [find_index(country, country_names) for country in countries_not_available]
adapted_country_correlation = np.delete(country_correlation, index_countries_not_available, 0)
adapted_country_correlation = np.delete(adapted_country_correlation, index_countries_not_available, 1)
# Next, we create a matrix where the GDP's are correlated with each other. Following the structure:
# - Entry(i,j) is the absolute value of the difference between the GDP per capita of country i and j.
# In[33]:
# create the matrix
gdps = np.zeros([adapted_country_correlation.shape[0], adapted_country_correlation.shape[0]])
countries_available = [country for country in country_names if country not in countries_not_available]
countries_available.sort()
# for every entry, calculate the entry
for row in range(len(countries_available)):
country_1 = countries_available[row]
country_1_gdp = float(data[find_index(country_1, data[:, 0].tolist()), 1])
for column in range(len(countries_available)):
country_2 = countries_available[column]
country_2_gdp = float(data[find_index(country_2, data[:, 0].tolist()), 1])
gdps[row, column] = abs(country_1_gdp - country_2_gdp)
gdps_norm = (gdps - np.mean(gdps)) / np.std(gdps)
# We can finally plot the GDP per capita difference heatmap.
# In[34]:
plt.subplots(1,2,figsize=(17,17))
plt.subplot(121)
sns.heatmap(gdps, square=True, cbar=None, yticklabels=False, xticklabels=False)
plt.title('GDP per capita difference', size=13)
plt.subplot(122)
sns.heatmap(adapted_country_correlation, square=True, cbar=None, yticklabels=False, xticklabels=False)
plt.title('Country capability correlation', size=13)
plt.show()
# **Left Figure**: The difference in GDP per capita of all of the countries in the database. The lighter the color in the heatmap, the bigger the difference in the GDP per capita between two countries.
#
# **Rigth Figure**: The knowledge capability correlation between two countries. The lighter the color, the more correlated their capabilities are.
#
# Let's study if these two matrixes are correlated in any way. We start by creating a function that flattens the above matrixes, by takingthe upper triangle and discarting anything below it (including the diagonal).
# In[35]:
def custom_flatten(matrix):
rows = matrix.shape[0]
cols = matrix.shape[1]
finalList = []
columnDisplacement = 1
for rowNumber in range(rows):
listToAppend = matrix[rowNumber, :][columnDisplacement::]
finalList.extend(listToAppend)
columnDisplacement += 1
return finalList
# After doing so, we determine two relevant statistics for the correlation study:
# In[36]:
rounding = 4
pearson_ = stats.pearsonr(custom_flatten(gdps), custom_flatten(adapted_country_correlation))[0]
p_value = stats.pearsonr(custom_flatten(gdps), custom_flatten(adapted_country_correlation))[1]
cos_sim = 1 - spatial.distance.cosine(custom_flatten(gdps), custom_flatten(adapted_country_correlation))
print 'Pearson correlation Index: {} (p-value of {})'.format(round(pearson_, rounding), round(p_value, rounding))
print 'Cosine similarity: {}'.format(round(cos_sim, rounding))
# The pearson correlation index shows that there is a very small positive correlation between GDP per capita and capability. Moreover, the p-value (< 0.05)comes to show that this assessment is 'statistically relevant'.
# #### 3.1.2. Country Profiles and Correlation: Denmark
# **GDP per capita difference**
#
# Let us first see how every country is different from Denmark in terms of GDP per capita. To do this, we plot all of the countries by difference in GDP per capita, and then order this plot.
# In[37]:
country = 'Denmark'
# find the matrix slice
country_index = find_index(country, countries_available)
raw_histogram_data_gdps = gdps[:, country_index]
raw_histogram_data_corr = adapted_country_correlation[:, country_index]
# remove the country itself from data and labels
clean_histogram_data_gpds = np.delete(raw_histogram_data_gdps, country_index)
clean_histogram_data_corr = np.delete(raw_histogram_data_corr, country_index)
clean_country_names = np.delete(countries_available, country_index)
# sort labels and data
bar_names = [x for _,x in sorted(zip(clean_histogram_data_gpds, clean_country_names))]
bars = sorted(clean_histogram_data_gpds)
#plot
plt.subplots(1,1,figsize=(15,7))
sns.barplot(np.arange(len(bars)), bars)
plt.xticks(np.arange(len(bars)), bar_names, rotation=90, fontsize=11)
plt.title('Country Profile: {}'.format(country))
plt.ylabel('GDP per capita difference in $US')
plt.show()
# As expected, the countries that have a closer GDP per capita are countries that are close geographically, but also countries that are close from an economic prespective.
# **GDP per capita and capability correlation**
#
# After visualizing the difference in GDP per capita, we wish to understand if this difference is related to capability correlations in any way.
#
# To do this, we produce a scatter plot where each data point corresponds to a particular country, and we print the correlation index.
# In[38]:
# scatter plot
fig, ax1 = plt.subplots(figsize=(15,7))
sns.regplot(clean_histogram_data_corr, clean_histogram_data_gpds, marker=".", color = '#0e103d')
plt.xlabel('Capability Correlation with {}'.format(country))
plt.ylabel('GDP per capita difference from {}'.format(country))
plt.title('Capability Correlation Vs. GDP per capita difference: Compared to {}.'.format(country))
plt.show()
correlation_score = stats.pearsonr(clean_histogram_data_corr, clean_histogram_data_gpds)
print 'The pearson correlation between these two variables is {} with a p-value of {}.'.format(correlation_score[0], correlation_score[1])
# There seems to be a significant negative correlation between these, which is expressed in the following way:
# - Countries with high GDP per capita difference have low capability correlations
# - Countries with low GDP per capita difference have high capability correlations
#
# Let us visualize these two clusters.
# **Density Plot**
#
# We produce a seaborn density plot.
# In[39]:
# density plot
fig, ax1 = plt.subplots(figsize=(15,7))
sns.kdeplot(clean_histogram_data_corr, clean_histogram_data_gpds, cmap="Reds", shade=True)
plt.xlabel('Capability Correlation with {}'.format(country))
plt.ylabel('GDP per capita difference from {}'.format(country))
plt.title('Capability Correlation Vs. GDP per capita difference density: Compared to {}.'.format(country))
plt.show()
# The above mentioned clusters are clear in this density plot.
# #### 3.1.3. Country Profiles and Correlation: Other Countries
# **Global Correlations- Scatter Plot**
# In[40]:
# create global lists for gdps difference and
globalGDP = np.asarray(custom_flatten(gdps))
globalCapabilityCorrelation = np.asarray(custom_flatten(adapted_country_correlation))
# scatter plot
fig, ax1 = plt.subplots(figsize=(15,7))
sns.regplot(globalCapabilityCorrelation, globalGDP,fit_reg=False, marker=".", color = '#a5668b')
plt.xlabel('Capability Correlation of country pairs')
plt.ylabel('GDP per capita difference of country pairs')
plt.title('Capability Correlation Vs. GDP per capita difference: Global')
plt.show()
# get correlation score
correlation_score = stats.pearsonr(globalCapabilityCorrelation, globalGDP)
print 'The pearson correlation between these two variables is {} with a p-value of {}.'.format(correlation_score[0], correlation_score[1])
# **Global Correlations - Scatter Plot Version 2**
#
# As can be noticed above, there are a lot of country pairs that have a 0 capability correlation. This can happen for severall reasons:
# - One of the countries does not have a significant number of assets.
# - Both countries have a very low number of assets.
#
# To understant the reach of this trait, the same plot is reproduced whyle ignoring the country pairs with 0 capability correlation.
# In[41]:
# create global lists for gdps difference and
globalGDP = np.asarray(custom_flatten(gdps))
globalCapabilityCorrelation = np.asarray(custom_flatten(adapted_country_correlation))
# eliminate pairs with no correlation
capabilityThreshold = 0.01
globalGDP_notNull = globalGDP[globalCapabilityCorrelation > capabilityThreshold]
globalCapabilityCorrelation_notNull = globalCapabilityCorrelation[globalCapabilityCorrelation > capabilityThreshold]
print 'A total of {} entries were eliminated from {}.'.format(len(globalCapabilityCorrelation) - len(globalCapabilityCorrelation_notNull), len(globalCapabilityCorrelation))
# scatter plot
fig, ax1 = plt.subplots(figsize=(15,7))
sns.regplot(globalCapabilityCorrelation_notNull, globalGDP_notNull,fit_reg=False, marker=".", color = '#69306d')
plt.xlabel('Capability Correlation of country pairs')
plt.ylabel('GDP per capita difference of country pairs')
plt.title('Capability Correlation Vs. GDP per capita difference: Global (Excluded if capability less than {})'.format(capabilityThreshold))
plt.show()
# get correlation score
correlation_score = stats.pearsonr(globalCapabilityCorrelation_notNull, globalGDP_notNull)
print 'The pearson correlation between these two variables is {} with a p-value of {}.'.format(correlation_score[0], correlation_score[1])
# Let us plot some guiding lines that will help us visualize the logic of this plot:
# In[42]:
# scatter plot
fig, ax1 = plt.subplots(figsize=(15,7))
sns.regplot(globalCapabilityCorrelation_notNull, globalGDP_notNull,fit_reg=False, marker=".", color = '#69306d')
x1 = 0.0
x2 = 0.1
y1 = 10000
y2 = 0
for k in range(9):
plt.plot([x1, x2], [y1, y2], ls="--", c='grey', lw=0.8)
y1 = y1 + 10000
x2 = x2 + 0.1
plt.xlabel('Capability Correlation of country pairs')
plt.ylabel('GDP per capita difference of country pairs')
plt.title('Capability Correlation Vs. GDP per capita difference: Global (Excluded if capability less than {})'.format(capabilityThreshold))
plt.show()
# Let us investigate some outliers:
# In[43]:
gdpPerCapitaLowerLimit = 45000
capabilityCorrelationLowerLimit = 0.5
print 'Outliers'
for i in range(len(countries_available)):
for j in range(len(countries_available)):
if np.triu(gdps, 1)[i,j]>gdpPerCapitaLowerLimit and np.triu(adapted_country_correlation, 1)[i,j]> capabilityCorrelationLowerLimit:
print countries_available[i],'-', countries_available[j]
# **Global Correlations- Density Plot**
# In[44]:
# density plot
fig, ax1 = plt.subplots(figsize=(15,7))
sns.kdeplot(globalCapabilityCorrelation, globalGDP, cmap="Blues", shade=True, cbar = True)
plt.xlabel('Capability Correlation of country pairs')
plt.ylabel('GDP per capita difference of country pairs')
plt.title('Capability Correlation Vs. GDP per capita difference density plot: Global')
plt.show()
plt.subplots(1,2,figsize=(15,7))
plt.subplot(121)
sns.kdeplot(globalCapabilityCorrelation, shade=True)
plt.title('Global correlation distribution')
plt.subplot(122)
sns.kdeplot(globalGDP, shade=True)
plt.title('Global GDP per capita difference distribution')
plt.show()
# **GDP p. capita - Capability Correlation for every country**
#
# To better understand this, we now study this correlation for every country.
# In[45]:
pearson_dict = {}
# for each country selected
for ind_country in countries_available:
# find the matrix slice
country_index = find_index(ind_country, countries_available)
histogram_data_gdps = gdps[:, country_index]
histogram_data_corr = adapted_country_correlation[:, country_index]
# remove the country itself from data and labels
histogram_data_gpds = np.delete(histogram_data_gdps, country_index)
histogram_data_corr = np.delete(histogram_data_corr, country_index)
clean_country_names = np.delete(countries_available, country_index)
# add entry to a dictionnary that dictionnary[country] = pearson correlation value
pearson_dict[ind_country] = stats.pearsonr(histogram_data_corr, histogram_data_gpds)[0]
sorted_dict = sorted(pearson_dict.items(), key=operator.itemgetter(1))
b_countries = [e[0] for e in sorted_dict]
correlations = [e[1] for e in sorted_dict]
plt.subplots(1,1,figsize=(15,7))
sns.barplot(np.arange(len(correlations)), correlations)
plt.xticks(np.arange(len(correlations)), b_countries, rotation=90, fontsize=11)
plt.title('GDP-Capability Correlation index by Country')
plt.show()
# #### 3.1.4. Utilizing the average GDP per capita
# In this part of the analysis we will introduce the average gdp per capita between two countries, let's start by creating the matrix.
# In[46]:
# create the matrix
gdps_average = np.zeros([adapted_country_correlation.shape[0], adapted_country_correlation.shape[0]])
countries_available = [country for country in country_names if country not in countries_not_available]
countries_available.sort()
# for every entry, calculate the entry
for row in range(len(countries_available)):
country_1 = countries_available[row]
country_1_gdp = float(data[find_index(country_1, data[:, 0].tolist()), 1])
for column in range(len(countries_available)):
country_2 = countries_available[column]
country_2_gdp = float(data[find_index(country_2, data[:, 0].tolist()), 1])
gdps_average[row, column] = (country_1_gdp + country_2_gdp) / 2.0
# In[47]:
plt.subplots(1,1,figsize=(13, 13))
plt.subplot(111)
sns.heatmap(gdps_average, square=True, cbar=True, yticklabels=countries_available, xticklabels=countries_available)
plt.title('GDP per capita average', size=13)
plt.show()
# In[48]:
globalGDP = np.asarray(custom_flatten(gdps))
globalCapabilityCorrelation = np.asarray(custom_flatten(adapted_country_correlation))
globalGdpAverage = np.asarray(custom_flatten(gdps_average)) / 800
# eliminate pairs with no correlation
capabilityThreshold = 0.01
globalGDP_notNull = globalGDP[globalCapabilityCorrelation > capabilityThreshold]
globalCapabilityCorrelation_notNull = globalCapabilityCorrelation[globalCapabilityCorrelation > capabilityThreshold]
globalGdpAverage_notNull = globalGdpAverage[globalCapabilityCorrelation > capabilityThreshold]
# scatter plot
fig, ax1 = plt.subplots(figsize=(15,7))
plt.scatter(globalCapabilityCorrelation_notNull, globalGDP_notNull, s=globalGdpAverage_notNull, marker="o")
plt.xlabel('Capability Correlation of country pairs')
plt.ylabel('GDP per capita difference of country pairs')
plt.title('Capability Correlation Vs. GDP per capita difference: Global (Excluded if capability less than {})'.format(capabilityThreshold))
plt.show()
# In[49]:
globalGDP = np.asarray(custom_flatten(gdps))
globalCapabilityCorrelation = np.asarray(custom_flatten(adapted_country_correlation))
globalGdpAverage = np.asarray(custom_flatten(gdps_average))
# eliminate pairs with no correlation
capabilityThreshold = 0.01
globalGDP_notNull = globalGDP[globalCapabilityCorrelation > capabilityThreshold]
globalCapabilityCorrelation_notNull = globalCapabilityCorrelation[globalCapabilityCorrelation > capabilityThreshold]
globalGdpAverage_notNull = globalGdpAverage[globalCapabilityCorrelation > capabilityThreshold]
# scatter plot
fig, ax1 = plt.subplots(figsize=(20,10))
cm = plt.cm.get_cmap('RdYlBu')
hey = plt.scatter(globalCapabilityCorrelation_notNull, globalGDP_notNull, c=globalGdpAverage_notNull, s=45, marker=".", cmap=cm)
plt.xlabel('Capability Correlation between country pair')
plt.ylabel('Absolute GDP per capita difference between country pairs')
plt.title('Capability Correlation Vs. GDP per capita difference: Global (Excluded if capability less than {})'.format(capabilityThreshold))
cb = plt.colorbar(hey)
cb.set_label('Average GDP per capita of country pair')
plt.show()
# Interactive version [here.](https://plot.ly/~duarteocarmo/32)
# In[50]:
data_points_names = []
column_dis = 1
for i in range(len(countries_available)):
first_name = countries_available[i]
data_points_names.extend([(first_name, e) for e in countries_available[column_dis::]])
column_dis += 1
print 'Total numbers:'
print 'Lenght of name pairs: ', len(data_points_names)
print 'Length of data points: ', len(globalGDP)
country1 = 'Brazil'
country2 = 'Zimbabwe'
print 'For {} and {}'.format(country1, country2)
for i in range(len(data_points_names)):
if data_points_names[i] == (country1, country2):
index = i
if data_points_names[i] == (country2, country1):
index = i
print 'Index is: ', index
print 'GDP Difference: ',globalGDP[index]
print 'GDP Average: ',globalGdpAverage[index]
print 'Capability Correlation: ',globalCapabilityCorrelation[index]
# ### 3.2. Collaborations
# #### 3.2.1. Collaboration Matrix
# The goal of this part of the analysis is to understand if the number of collaborations between countries plays a part in their correlation.
#
# To understand this let us create a matrix of collaborations.
#
# We start by creating the right query and building the matrix.
# In[51]:
# create Query
colabQuery = """ MATCH (a:Asset)-[:LOCATED_IN]->(ac:Country)
MATCH (b:Asset)-[:LOCATED_IN]->(bc:Country)
WHERE a.id = b.id AND ac.name <> bc.name
RETURN ac.name, bc.name ,count(a.id)
ORDER BY count(a.id) DESC"""
# extract matrix from query
colabData = DataFrame(connection_to_graph.data(colabQuery)).as_matrix()
# create empty collaboration matrix
colabMatrix = np.zeros([adapted_country_correlation.shape[0], adapted_country_correlation.shape[0]])
for row in range(len(countries_available)):
firstCountry = countries_available[row]
for col in range(len(countries_available)):
secondCountry = countries_available[col]
# if first and second country match, put value in matrix and break loop.
for data_row in colabData:
if firstCountry == data_row[0] and secondCountry == data_row[1]:
found = 1
colabMatrix[row,col] = data_row[2]
break
# We start by plotting the heatmap of our collaboration matrix.
# In[52]:
plt.subplots(1,1,figsize=(13, 13))
plt.subplot(111)
sns.heatmap(colabMatrix, square=True, yticklabels=countries_available, xticklabels=countries_available)
plt.title('Heatmap of country collaborations', size=13)
plt.show()
# Let us create a verification tool to understand if everything is working properly.
# In[53]:
firstCountry= 'Germany'
secondCountry= 'United Kingdom'
firstIndex = countries_available.index(firstCountry)
secondIndex = countries_available.index(secondCountry)
print '{} and {} have {} assets in common. Value: {}; Symmetrical Value: {}.'.format(firstCountry, secondCountry, colabMatrix[firstIndex, secondIndex], colabMatrix[firstIndex, secondIndex], colabMatrix[secondIndex, firstIndex])
# This corresponds to the neo4j value found in the database.
# #### 3.2.2. Collaborations and Capabilities
# We now seek to understand the relationship between collaborations and capacbility correlation in our data.
# In[54]:
# create global lists for gdps difference and
globalCollaborations = np.asarray(custom_flatten(colabMatrix))
globalCapabilityCorrelation = np.asarray(custom_flatten(adapted_country_correlation))
# scatter plot
fig, ax1 = plt.subplots(figsize=(15,7))
sns.regplot(globalCollaborations, globalCapabilityCorrelation,fit_reg=False, marker=".", color = '#02c39a')
plt.ylabel('Capability Correlation of Country Pairs')
plt.xlabel('Number of Shared Assets of Country Pair')
plt.title('Capability Correlation and Scientific Collaboration by country pair: Global')
# annotations
plt.annotate('Similar but not collaborating.', xy=(11, 0.7), xytext=(20, 0.75),arrowprops=dict(facecolor='black', shrink=0.05))
plt.annotate('Different and not collaborating.', xy=(11, 0.1), xytext=(20, 0.15),arrowprops=dict(facecolor='red', shrink=0.05))
plt.annotate('Similar and collaborating.', xy=(100, 0.7), xytext=(110, 0.75),arrowprops=dict(facecolor='yellow', shrink=0.05))
plt.annotate('Different and collaborating.', xy=(100, 0.1), xytext=(110, 0.15),arrowprops=dict(facecolor='blue', shrink=0.05))
plt.annotate("",xy=(60, 0.0), xycoords='data',xytext=(60, 0.9), textcoords='data',arrowprops=dict(arrowstyle="-",connectionstyle="arc3"),)
plt.annotate("",xy=(-10, 0.4), xycoords='data',xytext=(125, 0.4), textcoords='data',arrowprops=dict(arrowstyle="-",connectionstyle="arc3"),)
plt.show()
# get correlation score
correlation_score = stats.pearsonr(globalCapabilityCorrelation, globalCollaborations)
print 'The pearson correlation between these two variables is {} with a p-value of {}.'.format(correlation_score[0], correlation_score[1])
# In[55]:
print 'Different and not Collaborating:'
counter = 0
for i in range(len(countries_available)):
for j in range(len(countries_available)):
if colabMatrix[i,j]<60 and adapted_country_correlation[i,j]< 0.4:
print countries_available[i],'-', countries_available[j]
counter += 1
break
if counter == 4:
break
# In[56]:
print 'Different and Collaborating:'
counter = 0
for i in range(len(countries_available)):
for j in range(len(countries_available)):
if colabMatrix[i,j]>60 and adapted_country_correlation[i,j]< 0.4:
print countries_available[i],'-', countries_available[j]
counter += 1
break
if counter == 4:
break
# In[57]:
print 'Similar but not Collaborating:'
counter = 0
for i in range(len(countries_available)):
for j in range(len(countries_available)):
if colabMatrix[i,j]<60 and adapted_country_correlation[i,j]> 0.4 and adapted_country_correlation[i,j]< 0.8:
print countries_available[i],'-', countries_available[j]
counter += 1
break
if counter == 4:
break
# In[58]:
print 'Similar and Collaborating:'
counter = 0
for i in range(len(countries_available)):
for j in range(len(countries_available)):
if colabMatrix[i,j]>75 and adapted_country_correlation[i,j]> 0.4 and adapted_country_correlation[i,j]< 0.8:
print countries_available[i],'-', countries_available[j]
counter += 1
break
if counter == 4:
break
# #### 3.2.3. Normalized Collaborations and Capabilities
#
# In order to more deeply understand the relationship between collaborations and capabilities, we will normalized the collaborations part of the procedure. To do this, we must specify:
# - Old collaboration definition: Country `i` and country `j` have `z` assets that have both their name as location.
# - New **normalized** collaboration definition:
# `normalized_collaboration`= (` number of shared assets between country i and j`)/(` number of total possible collaborations between i and j`)
# Let us create a function that given a country returns its number of assets.
# In[59]:
def get_asset_number(country):
numberQuery = """ MATCH (a:Asset)-[:LOCATED_IN]->(ac:Country)
WHERE ac.name = "{}"
RETURN count(a)""".format(country)
return DataFrame(connection_to_graph.data(numberQuery)).as_matrix()[0][0]
# And we create the `normalizedColabMatrix`:
# In[60]:
normalizedColabMatrix = np.zeros(adapted_country_correlation.shape)
for rowNumber in range(len(countries_available)):
first_country = countries_available[rowNumber]
first_country_assets = get_asset_number(first_country)
for colNumber in range(len(countries_available)):
second_country = countries_available[colNumber]
second_country_assets = get_asset_number(second_country)
normalizedColabMatrix[rowNumber, colNumber] = colabMatrix[rowNumber, colNumber] / min(first_country_assets, second_country_assets)
# Let us check if everything is working properly:
# In[61]:
country_1 = 'Denmark'
country_2 = 'Portugal'
country_1_index = countries_available.index(country_1)
country_2_index = countries_available.index(country_2)
print 'Number of assets {}: '.format(country_1), get_asset_number(country_1)
print 'Number of assets {}: '.format(country_2), get_asset_number(country_2)
print 'Number of shared assets: ', colabMatrix[country_1_index, country_2_index]
print 'Number of normalized shared assets: ', normalizedColabMatrix[country_1_index, country_2_index]
# Since the maximum number of shared assets in this case is 180, the normalized shared assets as described above should be 25/180, which is indeed equal to 0.14.
# We can now reproduce a scatter plot where:
# - the `x` axis corresponds to the number of **normalized** shared assets between a country pair
# - the `y` axis corresponds to the capability correlation for that same country pair.
# In[62]:
# create global lists for gdps difference and
globalNormalizedCollaborations = np.asarray(custom_flatten(normalizedColabMatrix))
globalCapabilityCorrelation = np.asarray(custom_flatten(adapted_country_correlation))
# scatter plot
fig, ax1 = plt.subplots(figsize=(15,7))
sns.regplot(globalNormalizedCollaborations, globalCapabilityCorrelation,fit_reg=False, marker=".", color = '#028090')
plt.ylabel('Capability Correlation of Country Pairs')
plt.xlabel('Number of Normalized Shared Assets of Country Pair')
plt.title('Capability Correlation and Scientific Collaboration by country pair: Global')
# annotations
plt.annotate('Similar but not collaborating.', xy=(0.05, 0.6), xytext=(0.1, 0.75),arrowprops=dict(facecolor='black', shrink=0.05))
plt.annotate('Different and not collaborating.', xy=(0.05, 0.1), xytext=(0.1, 0.25),arrowprops=dict(facecolor='red', shrink=0.05))
plt.annotate('Similar and collaborating.', xy=(0.3, 0.6), xytext=(0.35, 0.75),arrowprops=dict(facecolor='yellow', shrink=0.05))
plt.annotate('Different and collaborating.', xy=(0.3, 0.1), xytext=(0.35, 0.25),arrowprops=dict(facecolor='green', shrink=0.05))
plt.annotate("",xy=(0.2, 0.0), xycoords='data',xytext=(0.2, 0.9), textcoords='data',arrowprops=dict(arrowstyle="-",connectionstyle="arc3"),)
plt.annotate("",xy=(0, 0.4), xycoords='data',xytext=(0.5, 0.4), textcoords='data',arrowprops=dict(arrowstyle="-",connectionstyle="arc3"),)
plt.annotate('(France; Lebanon)', xy=(0.83, 0.05), xytext=(0.7, 0.15),arrowprops=dict(facecolor='pink', shrink=0.05))
plt.annotate('(Germany; Austria)', xy=(0.53, 0.5), xytext=(0.6, 0.6),arrowprops=dict(facecolor='pink', shrink=0.05))
plt.show()
# get correlation score
correlation_score = stats.pearsonr(globalCapabilityCorrelation, globalNormalizedCollaborations)
print 'The pearson correlation between these two variables is {} with a p-value of {}.'.format(correlation_score[0], correlation_score[1])
print 'Capability Correlation Mean: ', np.mean(globalCapabilityCorrelation)
print 'Normalized Collaboration Mean: ', np.mean(globalNormalizedCollaborations)
# Interactive version [here.](https://plot.ly/~duarteocarmo/34/)
# In[63]:
from plotly.offline import download_plotlyjs, init_notebook_mode, plot, iplot
init_notebook_mode(connected=True)
from plotly.graph_objs import *
text_names = []
for pair in data_points_names:
text_names.append('{}/{}'.format(pair[0], pair[1]))
names = ['Different and not collaborating', 'Similar but not collaborating', 'Similar and collaborating', 'Different and collaborating']
colors = ['blue', 'red', 'green', 'orange']
indexes = [[], [], [], []]
for i in range(len(globalNormalizedCollaborations)):
if globalNormalizedCollaborations[i] < 0.2 and globalCapabilityCorrelation[i] < 0.4:
indexes[0].append(i)
if globalNormalizedCollaborations[i] < 0.2 and globalCapabilityCorrelation[i] > 0.4:
indexes[1].append(i)
if globalNormalizedCollaborations[i] > 0.2 and globalCapabilityCorrelation[i] > 0.4:
indexes[2].append(i)
if globalNormalizedCollaborations[i] > 0.2 and globalCapabilityCorrelation[i] < 0.4:
indexes[3].append(i)
data = []
for k in range(4):
data.append(Scatter(x=[globalNormalizedCollaborations[e] for e in indexes[k]] ,
y=[globalCapabilityCorrelation[e] for e in indexes[k]],
text = [text_names[e] for e in indexes[k]],
mode='markers',
name=names[k],
marker=Marker(color=colors[k], size=5, opacity=0.8)
))
layout = dict(title = 'Capability Correlation and Scientific Collaboration by country pair: Global',
xaxis=dict(title='Number of Normalized Shared Assets of Country Pair'),
yaxis=dict(title='Capability Correlation of Country Pairs'))
fig = dict(data=data, layout=layout)
iplot(fig,show_link=True)
# Let us analyze some of the datapoints:
# In[64]:
print 'Different and Collaborating (Limited):'
for i in range(len(countries_available)):
for j in range(len(countries_available)):
if np.triu(normalizedColabMatrix, 1)[i,j]>0.5 and np.triu(adapted_country_correlation, 1)[i,j]<0.4:
print countries_available[i],'-', countries_available[j]
# In[65]:
print 'Similar and Collaborating (Limited):'
for i in range(len(countries_available)):
for j in range(len(countries_available)):
if np.triu(normalizedColabMatrix, 1)[i,j]>0.3 and np.triu(adapted_country_correlation, 1)[i,j]>0.4:
print countries_available[i],'-', countries_available[j]
# ## 4. The case of Denmark
# ### 4.1. Visualizing Differences
# We will start by producing a macro visualization of the capability matrix of Denmark and the capability matrix of Sweden. For now, we will not focus on the exact capabilities taht differ, but just compare them side by side, without normalizing.
#
# We use the functions previsouly produced.
# In[66]:
# call functions
denmark = 'Denmark'
compare_with = 'Brazil'
colors = 'magma'
dk_matrix = get_country_matrix(denmark, normalization=False)
scnd_matrix = get_country_matrix(compare_with, normalization=False)
# create a subplot
plt.subplots(2,1,figsize=(17,17))
# first heatmap
plt.subplot(121)
sns.heatmap(dk_matrix, cmap=colors, cbar=None, square=True, xticklabels=False, yticklabels=False)
plt.title('Capability Matrix: {}'.format(denmark))
# second heatmap
plt.subplot(122)
sns.heatmap(scnd_matrix, cmap=colors, cbar=None, square=True, xticklabels=False, yticklabels=False)
plt.title('Capability Matrix: {}'.format(compare_with))
plt.show()
# Next, let us create the map of differences, where:
#
# differences[i, j] = abs(denmark[i,j] - other_country[i, j]) for every i and j
# In[67]:
cap_diff = np.absolute(dk_matrix - scnd_matrix)
# And plot the heatmap
# In[68]:
plt.subplots(1,1,figsize=(13, 13))
plt.subplot(111)
sns.heatmap(cap_diff, square=True, yticklabels=False, xticklabels=False)
plt.title('Differences between Denmark and {} as absolute values'.format(compare_with), size=13)
plt.show()
# ### 4.2. Understanding Differences
# Let us analyze the capability pairs where denmark and the other country have the most documents.
#
# We create a function that given a matrix, returns its top hits.
# In[69]:
def get_top_hits(countryMatrix, name):
"""
The function prints the top occurences if fed a matrix of occurences, it also prints other types of valuable info.
WARNING: Percentages are shown as 0 to 1.
"""
# list where all the values and indexes of matrix are stored
top = 10
values = []
indexes = []
no_duplicates = np.triu(countryMatrix, 1)
total_documents = np.sum(no_duplicates)
# loop through the matrix
for row_n in range(dk_matrix.shape[0]):
for col_n in range(dk_matrix.shape[1]):
values.append(no_duplicates[row_n, col_n])
indexes.append((row_n, col_n))
# order the indexes and get the top
Z = [indexes for _,indexes in sorted(zip(values,indexes))]
extremes = Z[-top :]
# create dataframe
term_Dataframe = pd.DataFrame(
{'First Term': [matrix_axis_names[e[0]] for e in extremes],
'Second Term': [matrix_axis_names[e[1]] for e in extremes],
'Number of Documents': [int(no_duplicates[e[0], e[1]]) for e in extremes],
'Percentage' : [no_duplicates[e[0], e[1]] / float(total_documents) for e in extremes],
})
# prepare dataframe
term_Dataframe = term_Dataframe[['First Term', 'Second Term','Number of Documents', 'Percentage']]
term_Dataframe = term_Dataframe.sort_values('Number of Documents', ascending=False)
# print everything
print 'The top hits for the {} matrix: '.format(name)
display(HTML(term_Dataframe.to_html(index=False)))
print 'The total number of documents is {}.'.format(int(total_documents))
print 'Note: Percentages are as 0-1 in this table. '
# And we run the function on both our countries.
#
# Denmark:
# In[70]:
get_top_hits(dk_matrix, denmark)
# We notice that outputs play a major role in the capability matrix. Biogas, ethanol and fermentation are some of the terms that appear the most.
#
# And the other country.
# In[71]:
get_top_hits(scnd_matrix, compare_with)
# We will now understand where the biggest differences are.
# In[72]:
# list where all the values and indexes of matrix are stored
dk_perc = dk_matrix / np.sum(np.triu(dk_matrix, 1)) # half only
other_perc = scnd_matrix / np.sum(np.triu(scnd_matrix, 1))
differences = dk_perc - other_perc
differences = np.absolute(differences)
values = []
indexes = []
no_duplicates = np.triu(differences, 1)
top = 20
# loop through the matrix
for row_n in range(differences.shape[0]):
for col_n in range(differences.shape[1]):
values.append(no_duplicates[row_n, col_n])
indexes.append((row_n, col_n))
# print the table
Z = [indexes for _,indexes in sorted(zip(values,indexes))]
extremes = list(reversed(Z[-top:]))
term_Dataframe = pd.DataFrame(
{'First Term': [matrix_axis_names[e[0]] for e in extremes],
'Second Term': [matrix_axis_names[e[1]] for e in extremes],
'Denmark Percentage': [dk_perc[e[0], e[1]] for e in extremes],
'{} Percentage'.format(compare_with): [other_perc[e[0], e[1]] for e in extremes],
'Difference in percentage': [no_duplicates[e[0], e[1]] for e in extremes]
})
term_Dataframe = term_Dataframe[['First Term', 'Second Term', 'Denmark Percentage', '{} Percentage'.format(compare_with), 'Difference in percentage']]
display(HTML(term_Dataframe.to_html(index=False)))
print 'Percentages are as 0-1 in this table for easy viz.'
# Here, some patterns start emerging, the top half of the list shows where the country we are comparing to has more capabilities when compared to Denmark. The bottom half of the table, shows where Denmark has more focus.
# ### 4.3. Country Spectrums: Revisited
# To further understand these capabilities, let us adopt a common spectral representation used in biology. By mapping each ccapability term pair and either a country has it or not.
#
# Let's start by building a function that gives us that same list for each country (e.g. its DNA).
# In[73]:
def get_country_values(country):
"""
Returns the country DNA, if 'root' then it returns all of the names of the term pairs.
"""
matrix = get_country_matrix(country, normalization=False)
matrix_tri = np.triu(matrix, 1)
values = []
indexes = []
# loop through the matrix
for row_n in range(matrix_tri.shape[0]):
for col_n in range(matrix_tri.shape[1]):
values.append(matrix_tri[row_n, col_n])
indexes.append((row_n, col_n))
if country == 'root':
term_tuples = ['{}/{}'.format(matrix_axis_names[a[0]], matrix_axis_names[a[1]]) for a in indexes]
return term_tuples
else:
return values
# Let us examplify with a samll subset of countries and term-pairs.
# #### 4.3.1. Country Spectrums: Zooming In
# In[74]:
# define countries
scope_countries = ['Norway', 'Denmark', 'Finland', 'Portugal', 'Spain', 'France', 'United Kingdom']
# create heatmap and names of capability terms array
scope_matrix = np.zeros((len(scope_countries), len(get_country_values('Denmark'))))
capability_pair_names = np.asarray(get_country_values('root'))
# build the matrix
for i in range(len(scope_countries)):
scope_matrix[i, :] = get_country_values(scope_countries[i])
# detect if a certain term pair is not used at all by computing the column sum
column_sum = np.sum(scope_matrix, axis=0)
zero_counter = 0
zero_indexes_array = []
for i in range(len(column_sum)):
if column_sum[i] == 0.0:
zero_counter += 1
zero_indexes_array.append(i)
# delete the empty term pairs
print 'The original shape was of {} countries and {} term pairs.'.format(scope_matrix.shape[0], scope_matrix.shape[1])
print '{}% of the term pairs were empty.'.format(zero_counter * 100 / len(column_sum))
scope_matrix = np.delete(scope_matrix, zero_indexes_array, 1)
capability_pair_names = np.delete(capability_pair_names, zero_indexes_array)
print 'The final shape is of {} countries and {} term pairs.'.format(scope_matrix.shape[0], scope_matrix.shape[1])
# limit the visualization
limit = 45
print 'Here, reduced to {} for visualization purposes.'.format(limit)
plt.subplots(1,1,figsize=(20, 5))
plt.subplot(111)
sns.heatmap(scope_matrix[:, 0:limit],cmap=ListedColormap(['white', 'black']), center=0.01, cbar=None, square=False, yticklabels=scope_countries, xticklabels=capability_pair_names[0:limit])
plt.title('Country Capability Spectral Representation: Zoom', size=15)
plt.show()
# Here, a black marker simply means that the country possesses an asset that countains that term pair.
# #### 4.3.2. Country Spectrums: Limited Countries
# Let us plot the full spectrum for these countries, keep in mind that the quantity of term pairs is important.
# In[75]:
plt.subplots(1,1,figsize=(25, 10))
plt.subplot(111)
sns.heatmap(scope_matrix,cmap=ListedColormap(['white', 'black']), center=0.01, cbar=None, square=False, yticklabels=scope_countries, xticklabels=False)
plt.title('Country Capability Spectral Representation: Limited Countries', size=15)
plt.show()
# Finally, let us try to map out all of the countries.
# #### 4.3.3. Country Spectrums: Full Representation
# In[76]:
# redefine countries
list_of_countries = [country_names[i] for i in list(np.load('Data/cluster_country_order.npy'))]
# prepare heatmap
jumbo_matrix = np.zeros((len(list_of_countries), len(get_country_values('Denmark'))))
# build heatmap
for i in range(len(list_of_countries)):
jumbo_matrix[i, :] = get_country_values(list_of_countries[i])
# delete 0 entries
column_sum = np.sum(jumbo_matrix, axis=0)
zero_counter = 0
zero_indexes_array = []
for i in range(len(column_sum)):
if column_sum[i] == 0.0:
zero_counter += 1
zero_indexes_array.append(i)
# adjust size to empy cells and output info
print 'The original shape was of {} countries and {} term pairs.'.format(jumbo_matrix.shape[0], jumbo_matrix.shape[1])
print '{}% was empty.'.format(zero_counter * 100 / len(column_sum))
jumbo_matrix = np.delete(jumbo_matrix, zero_indexes_array, 1)
print 'The new shape was of {} countries and {} term pairs.'.format(jumbo_matrix.shape[0], jumbo_matrix.shape[1])
plt.subplots(1,1,figsize=(20, 15))
plt.subplot(111)
sns.heatmap(jumbo_matrix,cmap=ListedColormap(['white', 'black']), center=0.01, cbar=None, square=False, yticklabels=list_of_countries, xticklabels=False)
plt.yticks(rotation=0)
plt.title('Country Capability Spectral Representation', size=15)
plt.show()
# #### 4.3.4. Country Spectrums: Pairs with more than X occurency
# In[77]:
country_threshold = 2
col_with_low_countries = []
col_good = []
for n_col in range(jumbo_matrix.shape[1]):
countries_with_pair = 0
for n_row in range(jumbo_matrix.shape[0]):
if jumbo_matrix[n_row, n_col] > 0:
countries_with_pair += 1
if countries_with_pair <= country_threshold:
col_with_low_countries.append(n_col)
else:
col_good.append(n_col)
print 'There were {} term pairs with less than {} countries using them. '.format(len(col_with_low_countries), country_threshold)
jumbo_matrix = np.delete(jumbo_matrix, col_with_low_countries, 1)
print 'The final shape is of {} countries and {} term pairs.'.format(jumbo_matrix.shape[0], jumbo_matrix.shape[1])
plt.subplots(1,1,figsize=(20, 15))
plt.subplot(111)
sns.heatmap(jumbo_matrix,cmap=ListedColormap(['white', 'black']), center=0.01, cbar=None, square=False, yticklabels=list_of_countries, xticklabels=False)
plt.yticks(rotation=0)
plt.title('Country Capability Spectral Representation: pairs with at least {} countries.'.format(country_threshold), size=15)
plt.show()
# In[78]:
country_limit = 11
plt.subplots(1,1,figsize=(25, 10))
plt.subplot(111)
sns.heatmap(jumbo_matrix[0:country_limit, :],cmap=ListedColormap(['white', 'black']), center=0.01, cbar=None, square=False, yticklabels=list_of_countries[0:country_limit], xticklabels=False)
plt.yticks(rotation=0)
plt.title('Country Capability Spectral Representation: pairs with at least {} countries.'.format(country_threshold), size=15)
plt.show()
# #### 4.3.5. Country Spectrums: Diving into pairs
# In[79]:
# prepare heatmap
jumbo_matrix = np.zeros((len(list_of_countries), len(get_country_values('Denmark'))))
capability_pair_names = np.asarray(get_country_values('root'))
# build heatmap
for i in range(len(list_of_countries)):
jumbo_matrix[i, :] = get_country_values(list_of_countries[i])
# In[80]:
# delete 0 entries
column_sum = np.sum(jumbo_matrix, axis=0)
zero_counter = 0
zero_indexes_array = []
for i in range(len(column_sum)):
if column_sum[i] == 0.0:
zero_counter += 1
zero_indexes_array.append(i)
# adjust size to empy cells and output info
print 'After deleting pairs with no occurencies:'
print 'The original shape was of {} countries and {} term pairs.'.format(jumbo_matrix.shape[0], jumbo_matrix.shape[1])
print '{}% was empty.'.format(zero_counter * 100 / len(column_sum))
jumbo_matrix = np.delete(jumbo_matrix, zero_indexes_array, 1)
capability_pair_names = np.delete(capability_pair_names, zero_indexes_array)
print 'The new shape was of {} countries and {} term pairs.'.format(jumbo_matrix.shape[0], jumbo_matrix.shape[1])
# **Capability pairs that only appear in one country:**
# In[81]:
pair_must_appear_in = 1
unique_country = 'Denmark'
number_of_unique_pairs = 0
print 'Pairs that only appear in {}:'.format(unique_country)
print ''
for column in range(len(capability_pair_names)):
name_of_pair = capability_pair_names[column]
counter = 0
countries_have_it = []
for row in range(len(list_of_countries)):
if jumbo_matrix[row, column] > 0.0:
counter += 1
countries_have_it.append(list_of_countries[row])
if counter == pair_must_appear_in and unique_country in countries_have_it:
number_of_unique_pairs += 1
print name_of_pair, countries_have_it, counter
print ''
print '{} has {} unique pairs.'.format(unique_country, number_of_unique_pairs)
# **Countries with the most unique pairs:**
# We create a function that given a country returns the number of total pairs that country and the number of pairs that are unique to that country.
# In[82]:
def number_of_unique_pairs(unique_country):
pair_must_appear_in = 1
number_of_unique_pairs = 0
total_pairs = 0
for column in range(len(capability_pair_names)):
name_of_pair = capability_pair_names[column]
counter = 0
countries_have_it = []
for row in range(len(list_of_countries)):
if jumbo_matrix[row, column] > 0.0:
if list_of_countries[row] == unique_country:
total_pairs += 1
counter += 1
countries_have_it.append(list_of_countries[row])
if counter == pair_must_appear_in and unique_country in countries_have_it:
number_of_unique_pairs += 1
return (number_of_unique_pairs, total_pairs)
# In[83]:
print '{} has {} pairs which {} are unique.'.format('Portugal', number_of_unique_pairs('Portugal')[1], number_of_unique_pairs('Portugal')[0])
# Let us define the uniqueness of a country as its proportion of unique pairs in relation to total pairs.
# In[84]:
def country_uniqueness(country):
division = float(number_of_unique_pairs(country)[0]) / number_of_unique_pairs(country)[1]
return division
# Let us create the uniqueness ranking:
# In[85]:
# create dataframe
term_Dataframe = pd.DataFrame(
{'Country': [country for country in list_of_countries],
'Uniqueness': [country_uniqueness(country) for country in list_of_countries],
'Unique Pairs': [number_of_unique_pairs(country)[0] for country in list_of_countries],
'Total Pairs': [number_of_unique_pairs(country)[1] for country in list_of_countries]
})
# prepare dataframe
term_Dataframe = term_Dataframe[['Country', 'Uniqueness', 'Unique Pairs', 'Total Pairs']]
term_Dataframe = term_Dataframe.sort_values('Uniqueness', ascending=False)
# print everything
display(HTML(term_Dataframe[:20].to_html(index=False)))
# In[86]:
dk = 'Denmark'
print '{} has an uniqueness of {} with {} pairs of which {} are unique.'.format(dk, country_uniqueness(dk), number_of_unique_pairs(dk)[1], number_of_unique_pairs(dk)[0])
# **Country word clouds:**
# In[87]:
country_for_cloud = 'Uganda'
index_for_cloud = list_of_countries.index(country_for_cloud)
jumbo_array = jumbo_matrix[index_for_cloud, :]
string = ''
pair_counter = 0
for i in range(len(capability_pair_names)):
if jumbo_array[i] > 0.0:
pair_counter += 1
string += ' {}'.format(capability_pair_names[i].replace('/', ' '))
print '{} has {} term pairs.'.format(country_for_cloud, pair_counter)
# In[88]:
text = string
wordcloud = WordCloud().generate(text)
print '{} cloud:'.format(country_for_cloud)
plt.subplots(1,1,figsize=(15, 5))
plt.subplot(111)
plt.imshow(wordcloud, interpolation='bilinear')
plt.axis("off")
plt.show()