Measuring the Innovation Impact of an Organization using Patents Citations¶
This notebook shows how to use the Dimensions Analytics API to analyze the innovation impact of an organization.
There are two ways to achieve this. The first approach counts direct links between patents and the GRID organization we are interested in (i.e., it counts how many patents’ inventors are affiliated to the GRID organization). This method is faster to implement and can be easily achieved via a single patents API query:
> search patents where assignees in ["grid.89170.37"] return patents limit 500
Returned Patents: 192
---
[1] METHODS AND SYSTEMS FOR OBJECT IDENTIFICATION AND FOR AUTHENTICATION (id: https://app.dimensions.ai/details/patent/WO-2007149621-A3 )
[2] ADENOVIRAL VECTOR-BASED MALARIA VACCINES (id: https://app.dimensions.ai/details/patent/EP-1929021-A2 )
[3] MULTIPLE BAND SHORT WAVE INFRARED MOSAIC ARRAY FILTER (id: https://app.dimensions.ai/details/patent/WO-2016040755-A1 )
[4] ARMOR PLATE (id: https://app.dimensions.ai/details/patent/WO-2011142867-A3 )
..etc..
The second method counts indirect links via publications, hence it permits to gain some insight into the indirect innovation impact of a research organization.
This is the method we’ll be focusing on, in this tutorial. The goal therefore is to extract and inspect patents that cite publications from the research organization in question.
Since the various content-types included in the Dimensions database are deeply interlinked, the Dimensions APIs allow to perform this analysis via a few simple steps:
We start from a GRID identifier (representing a research organization in Dimensions)
We use the publications API to extract all publications where at least one author is/as affiliated to the GRID organization, for a selected time-period
We then use the patents API to discover patents that include citations to any of those publications
Finally, we analyse the patents data to highlight trends e.g. about countries, inventors etc..
Prerequisites¶
This notebook assumes you have installed the Dimcli library and are familiar with the Getting Started tutorial.
[1]:
!pip install dimcli plotly tqdm -U --quiet
import dimcli
from dimcli.utils import *
import os, sys, time, json
from tqdm.notebook import tqdm as progressbar
import pandas as pd
import plotly.express as px
from plotly.offline import plot
if not 'google.colab' in sys.modules:
# make js dependecies local / needed by html exports
from plotly.offline import init_notebook_mode
init_notebook_mode(connected=True)
print("==\nLogging in..")
# https://digital-science.github.io/dimcli/getting-started.html#authentication
ENDPOINT = "https://app.dimensions.ai"
if 'google.colab' in sys.modules:
import getpass
KEY = getpass.getpass(prompt='API Key: ')
dimcli.login(key=KEY, endpoint=ENDPOINT)
else:
KEY = ""
dimcli.login(key=KEY, endpoint=ENDPOINT)
dsl = dimcli.Dsl()
==
Logging in..
Dimcli - Dimensions API Client (v0.8.2)
Connected to: https://app.dimensions.ai - DSL v1.28
Method: dsl.ini file
1. Choosing a GRID Research Organization¶
For the purpose of this exercise, we are going to use grid.4305.2 (The Open University, UK). Feel free to change the parameters below as you want, eg by choosing another GRID organization.
[3]:
GRIDID = "grid.10837.3d" #@param {type:"string"}
#@markdown The start/end year of publications used to extract patents
YEAR_START = 2005 #@param {type: "slider", min: 1950, max: 2020}
YEAR_END = 2015 #@param {type: "slider", min: 1950, max: 2020}
if YEAR_END < YEAR_START:
YEAR_END = YEAR_START
from IPython.core.display import display, HTML
display(HTML('---<br /><a href="{}">Open in Dimensions ⧉</a>'.format(dimensions_url(GRIDID))))
#@markdown ---
2. Extracting Publications Data¶
By looking at the Dimensions API data model, we can see that Patents and Publications are connected by a property called publication_ids
, which goes from Patents to Publications. This property represents the publications citations found in patents.
Hence, we need to 1. query for all publications with authors affiliated to our GRID ID 2. query for patents citing these publications
[4]:
# Get full list of publications linked to this organization for the selected time frame
q = f"""search publications
where research_orgs.id="{GRIDID}"
and year in [{YEAR_START}:{YEAR_END}]
return publications[id+doi+title+type+journal+year+research_orgs+researchers+category_for+times_cited]"""
print("===\n", q, "\n===")
pubs_json = dsl.query_iterative(q, limit=1000)
pubs = pubs_json.as_dataframe()
===
search publications
where research_orgs.id="grid.10837.3d"
and year in [2005:2015]
return publications[id+doi+title+type+journal+year+research_orgs+researchers+category_for+times_cited]
===
Starting iteration with limit=1000 skip=0 ...
0-1000 / 9039 (4.57s)
1000-2000 / 9039 (5.63s)
2000-3000 / 9039 (2.69s)
3000-4000 / 9039 (2.73s)
4000-5000 / 9039 (2.73s)
5000-6000 / 9039 (2.44s)
6000-7000 / 9039 (1.99s)
7000-8000 / 9039 (2.19s)
8000-9000 / 9039 (2.14s)
9000-9039 / 9039 (1.02s)
===
Records extracted: 9039
[5]:
pubs.head()
[5]:
doi | research_orgs | year | researchers | id | times_cited | title | category_for | type | journal.id | journal.title | |
---|---|---|---|---|---|---|---|---|---|---|---|
0 | 10.1108/hcs-07-2015-0013 | [{'id': 'grid.10837.3d', 'types': ['Education'... | 2015 | [{'id': 'ur.014121733420.41', 'last_name': 'Wh... | pub.1028750505 | 2 | Do people choose to be homeless? An existentia... | [{'id': '3448', 'name': '1608 Sociology'}, {'i... | article | jour.1046873 | Housing Care and Support |
1 | 10.5194/gmdd-8-10677-2015 | [{'id': 'grid.9026.d', 'types': ['Education'],... | 2015 | [{'id': 'ur.015722150315.42', 'last_name': 'Ho... | pub.1038820736 | 0 | PLASIM-GENIE: a new intermediate complexity AOGCM | [{'id': '2204', 'name': '04 Earth Sciences'}, ... | article | jour.1371971 | Geoscientific Model Development Discussions |
2 | 10.5194/esurf-3-587-2015 | [{'id': 'grid.463945.9', 'types': ['Facility']... | 2015 | [{'id': 'ur.015045402162.42', 'last_name': 'Hi... | pub.1014068242 | 6 | Perspective – synthetic DEMs: A vital underpin... | [{'id': '2204', 'name': '04 Earth Sciences'}, ... | article | jour.1146353 | Earth Surface Dynamics |
3 | 10.1108/mhrj-07-2014-0025 | [{'id': 'grid.10837.3d', 'types': ['Education'... | 2015 | [{'id': 'ur.014121733420.41', 'last_name': 'Wh... | pub.1045552756 | 1 | Shared dilemmas, choice and autonomy in the ma... | [{'id': '3177', 'name': '1117 Public Health an... | article | jour.1023878 | Mental Health Review Journal |
4 | 10.1108/jap-11-2014-0035 | [{'id': 'grid.10837.3d', 'types': ['Education'... | 2015 | [{'id': 'ur.07357206671.63', 'last_name': 'Mat... | pub.1046891576 | 0 | Bruising in older adults: what do social worke... | [{'id': '3177', 'name': '1117 Public Health an... | article | jour.1023876 | The Journal of Adult Protection |
Quick look at publications statistics¶
[6]:
px.histogram(pubs,
x="year",
color="type",
barmode="group",
title=f"Publication distribution by year - {GRIDID}")
What are the main subject areas?¶
We can use the Field of Research categories information in publications to obtain a breakdown of the publications by subject areas.
This can be achieved by ‘exploding’ the category_for
data into a separate table, since there can be more than one category per publication. The new categories table also retains some basic info about the publications it relates to eg journal, title, publication id etc.. so to make it easier to analyse the data.
[7]:
pubs_categories = pubs.explode('category_for')
pubs_categories.dropna(subset=["category_for"], inplace=True)
def for_nice_name(for_dict):
"transforms a category JSON into a nice looking title"
if type(for_dict) == dict:
name = for_dict['name']
return ''.join([i for i in name if not i.isdigit()])
else:
return ""
# new col for nice name
pubs_categories["category_for_name"] = pubs_categories['category_for'].apply(lambda x: for_nice_name(x))
# new col for tot-pubs count
pubs_categories['count_pubs'] = pubs_categories.groupby("category_for_name")['id'].transform('count')
Let’s view the top categories using a pie chart.
[8]:
categories = pubs_categories.drop_duplicates(subset="category_for_name").sort_values("count_pubs", ascending=False)[['category_for_name', 'count_pubs']]
px.pie(categories[:20],
names="category_for_name", # the dimension for the slices
values="count_pubs", # the metric
color_discrete_sequence=px.colors.sequential.Bluyl,
title=f"Top FOR categories")
3. Extracting Patents linked to Publications¶
In this section we extract all patents linked to the publications dataset previously created. The steps are the following:
we loop over the publication IDs and create patents queries, via the referencing
publication_ids
field of patentswe collate all patens data, remove duplicates from patents and save the results
finally, we count patents per publication and enrich the original publication dataset with these numbers
[9]:
#
# the main patents query
#
q = """search patents
where publication_ids in {}
return patents[basics+publication_ids+category_for]"""
BATCHSIZE = 400
VERBOSE = False # set to True to see patents extraction logs
#
# loop through all pub IDs in chunks and query patents
#
print("===\nExtracting patents data ...")
patents_json = []
pubsids = pubs['id']
for chunk in progressbar(list(chunks_of(list(pubsids), 400))):
data = dsl.query_iterative(q.format(json.dumps(chunk)), verbose=VERBOSE)
patents_json += data.patents
time.sleep(1)
patents = pd.DataFrame().from_dict(patents_json)
patents.drop_duplicates(subset='id', inplace=True)
print("Patents found: ", len(patents))
===
Extracting patents data ...
Patents found: 158
Let’s preview the data
[10]:
patents.head(5)
[10]:
year | assignee_names | assignees | title | publication_date | id | publication_ids | category_for | filing_status | inventor_names | granted_year | times_cited | |
---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 2014 | [UNIV OPEN] | [{'id': 'grid.10837.3d', 'name': 'The Open Uni... | ENGINEERED NEURAL TISSUE | 2015-02-05 | WO-2015015185-A1 | [pub.1038537221, pub.1007759342, pub.104762245... | [{'id': '2581', 'name': '0601 Biochemistry and... | Application | [PHILLIPS, JAMES, GEORGIOU, Melanie] | NaN | NaN |
1 | 2014 | [UCL Business Ltd, THE OPEN UNIV, UCL BUSINESS... | [{'id': 'grid.83440.3b', 'name': 'University C... | Engineered neural tissue | 2018-06-12 | US-9993581-B2 | [pub.1022718673, pub.1000691651, pub.103853722... | [{'id': '2581', 'name': '0601 Biochemistry and... | Grant | [James Phillips, Melanie Georgiou] | 2018.0 | NaN |
2 | 2017 | [PROTHENA BIOSCIENCES LTD] | [{'id': 'grid.482406.c', 'city_name': 'Dublin'... | ANTI-MCAM ANTIBODIES AND ASSOCIATED METHODS OF... | 2017-09-08 | WO-2017149513-A1 | [pub.1036841477, pub.1014162397, pub.104598330... | NaN | Application | [NESS, DANIEL KEITH, FLANAGAN, KENNETH] | NaN | NaN |
3 | 2015 | [Commissariat a lEnergie Atomique et aux Energ... | [{'id': 'grid.437359.f', 'city_name': 'Bernin'... | PROCESS FOR CONNECTING TWO SUBSTRATES | 2016-06-02 | DE-102015223347-A1 | [pub.1039579399] | [{'id': '2921', 'name': '0912 Materials Engine... | Application | [Didier Landru, Capucine Delage, Franck Fourne... | NaN | NaN |
5 | 2016 | [Semiconductor Manufacturing International Sha... | [{'id': 'grid.471325.6', 'city_name': 'Shangha... | Buried-channel MOSFET and a surface-channel MO... | 2018-08-28 | US-10062704-B2 | [pub.1061595798, pub.1061593545, pub.1061462502] | [{'id': '2471', 'name': '0306 Physical Chemist... | Grant | [Tzu Yin Chiu, Clifford Ian Drowley, Leong Tee... | 2018.0 | NaN |
Enriching publications with patents citations metrics¶
Each patent record contains all the publication_ids
it cites, so we can take this metric so to enrich the original publications dataset we created above.
[ ]:
def count_patents_per_pub(pubid):
global patents
return len(patents[patents['publication_ids'].str.contains(pubid)])
# turn lists into strings to ensure compatibility with CSV loaded data
# see also: https://stackoverflow.com/questions/23111990/pandas-dataframe-stored-list-as-string-how-to-convert-back-to-list
patents['publication_ids'] = patents['publication_ids'].apply(lambda x: ','.join(map(str, x)))
progressbar.pandas()
pubs['patents'] = pubs['id'].progress_apply(lambda x: count_patents_per_pub(x))
Now the patents
column gives us the top publications by number of citing patents
[12]:
pubs.sort_values("patents", ascending=False).head()
[12]:
doi | research_orgs | year | researchers | id | times_cited | title | category_for | type | journal.id | journal.title | patents | |
---|---|---|---|---|---|---|---|---|---|---|---|---|
8508 | 10.1096/fj.04-3458fje | [{'id': 'grid.428999.7', 'name': 'Pasteur Inst... | 2005 | [{'id': 'ur.01351646547.75', 'first_name': 'Ba... | pub.1002742563 | 846 | Blood‐brain barrier‐specific properties of a h... | [{'id': '3120', 'name': '1109 Neurosciences'},... | article | jour.1017429 | The FASEB Journal | 16 |
5220 | 10.1021/bc900397s | [{'id': 'grid.10837.3d', 'country_name': 'Unit... | 2010 | [{'id': 'ur.01124615125.34', 'first_name': 'Ch... | pub.1055155906 | 37 | Modification of thiol functionalized aptamers ... | [{'id': '2203', 'name': '03 Chemical Sciences'... | article | jour.1100499 | Bioconjugate Chemistry | 14 |
2903 | 10.1096/fj.11-201384 | [{'id': 'grid.462098.1', 'types': ['Facility']... | 2012 | [{'id': 'ur.01027626121.41', 'last_name': 'Li'... | pub.1033473743 | 84 | Cell‐penetrating anti‐GFAP VHH and correspondi... | [{'id': '3120', 'name': '1109 Neurosciences'},... | article | jour.1017429 | The FASEB Journal | 9 |
8318 | 10.1039/b600709k | [{'id': 'grid.493299.c', 'name': 'Institut Lav... | 2006 | [{'id': 'ur.01040541162.25', 'first_name': 'Su... | pub.1014463103 | 114 | An EXAFS study of the formation of a nanoporou... | [{'id': '2203', 'name': '03 Chemical Sciences'... | article | jour.1297159 | Chemical Communications | 5 |
8726 | 10.1196/annals.1342.014 | [{'id': 'grid.10837.3d', 'name': 'The Open Uni... | 2005 | [{'id': 'ur.01333733704.35', 'first_name': 'Ra... | pub.1004641182 | 11 | Amyloid Precursor Protein: From Synaptic Plast... | [{'id': '3120', 'name': '1109 Neurosciences'},... | article | jour.1002487 | Annals of the New York Academy of Sciences | 5 |
4. Patents Data Analysis¶
Now that we have extracted all the data we need, let’s start exploring them by building a few visualizations.
How many patents per year?¶
[13]:
px.histogram(patents, x="year",
color="filing_status",
barmode="group",
title=f"Patents referencing publications from {GRIDID} - by year")
Who is filing the patents?¶
This can be done by looking at the field assigness
of patent. Since the field contains nested information, first we need to extract it into its own table (similarly to what we’ve done above with publications categories).
[14]:
# ensure the key exists in all rows (even if empty)
from dimcli.shortcuts import normalize_key
normalize_key('assignees', patents_json)
# explode assigness into separate table
patents_assignees = pd.json_normalize(patents_json,
record_path=['assignees'],
meta=['id', 'year', 'title'],
meta_prefix="patent_",
errors="ignore")
top_assignees = patents_assignees.groupby(['name', 'country_name'],
as_index=False).count().sort_values(by="patent_id", ascending=False)
# preview the data: ps the patent_id column is the COUNT of patents
top_assignees[['name', 'country_name', 'patent_id']].head()
[14]:
name | country_name | patent_id | |
---|---|---|---|
51 | Pasteur Institute | France | 11 |
21 | French National Centre for Scientific Research | France | 10 |
20 | French Institute of Health and Medical Research | France | 10 |
66 | The Open University | United Kingdom | 8 |
85 | Wisconsin Alumni Research Foundation | United States | 6 |
[15]:
px.bar(top_assignees,
x="name", y="patent_id",
hover_name="name", color="country_name",
height=900,
title=f"Top Assignees for patents referencing publications from {GRIDID}")
[16]:
px.scatter(patents_assignees,
x="name", y="country_name",
color="patent_year", hover_name="name",
height = 1000,
hover_data=["id", "patent_id"], marginal_y="histogram",
title=f"Assignees for patents referencing publications from {GRIDID} - Yearly breakdown")
What are the publications most frequenlty referenced in patents?¶
[17]:
pubs_cited = pubs.query("patents > 0 ").sort_values('patents', ascending=False).copy()
pubs_cited.head()
[17]:
doi | research_orgs | year | researchers | id | times_cited | title | category_for | type | journal.id | journal.title | patents | |
---|---|---|---|---|---|---|---|---|---|---|---|---|
8508 | 10.1096/fj.04-3458fje | [{'id': 'grid.428999.7', 'name': 'Pasteur Inst... | 2005 | [{'id': 'ur.01351646547.75', 'first_name': 'Ba... | pub.1002742563 | 846 | Blood‐brain barrier‐specific properties of a h... | [{'id': '3120', 'name': '1109 Neurosciences'},... | article | jour.1017429 | The FASEB Journal | 16 |
5220 | 10.1021/bc900397s | [{'id': 'grid.10837.3d', 'country_name': 'Unit... | 2010 | [{'id': 'ur.01124615125.34', 'first_name': 'Ch... | pub.1055155906 | 37 | Modification of thiol functionalized aptamers ... | [{'id': '2203', 'name': '03 Chemical Sciences'... | article | jour.1100499 | Bioconjugate Chemistry | 14 |
2903 | 10.1096/fj.11-201384 | [{'id': 'grid.462098.1', 'types': ['Facility']... | 2012 | [{'id': 'ur.01027626121.41', 'last_name': 'Li'... | pub.1033473743 | 84 | Cell‐penetrating anti‐GFAP VHH and correspondi... | [{'id': '3120', 'name': '1109 Neurosciences'},... | article | jour.1017429 | The FASEB Journal | 9 |
8726 | 10.1196/annals.1342.014 | [{'id': 'grid.10837.3d', 'name': 'The Open Uni... | 2005 | [{'id': 'ur.01333733704.35', 'first_name': 'Ra... | pub.1004641182 | 11 | Amyloid Precursor Protein: From Synaptic Plast... | [{'id': '3120', 'name': '1109 Neurosciences'},... | article | jour.1002487 | Annals of the New York Academy of Sciences | 5 |
8318 | 10.1039/b600709k | [{'id': 'grid.493299.c', 'name': 'Institut Lav... | 2006 | [{'id': 'ur.01040541162.25', 'first_name': 'Su... | pub.1014463103 | 114 | An EXAFS study of the formation of a nanoporou... | [{'id': '2203', 'name': '03 Chemical Sciences'... | article | jour.1297159 | Chemical Communications | 5 |
[18]:
px.bar(pubs_cited[:1000],
color="type",
x="year", y="patents",
hover_name="title", hover_data=["journal.title"],
title=f"Top Publications from {GRIDID} mentioned in patents, by year of publication")
What are the main subject areas of referenced publications?¶
[19]:
THRESHOLD_PUBS = 1000
citedids = list(pubs_cited[:THRESHOLD_PUBS]['id'])
pubs_categories_cited = pubs_categories[pubs_categories['id'].isin(citedids)]
[20]:
px.scatter(pubs_categories_cited, x="year", y="category_for_name", color="type",
hover_name="title",
hover_data=["doi", "year", "journal.title"],
height=800,
marginal_x="histogram", marginal_y="histogram",
title=f"Top {THRESHOLD_PUBS} {GRIDID} publications cited by patents - by subject area")
Is there a correlation between publication citations and patents citations?¶
Note: if the points on a scatterplot graph produce a lower-left-to-upper-right pattern (see below), that is indicative of a positive correlation between the two variables. This pattern means that when the score of one observation is high, we expect the score of the other observation to be high as well, and vice versa.
[21]:
px.scatter(pubs, x="patents", y="times_cited",
title=f"Patents citations VS Publication citations")
Where to go from here¶
In this Dimensions Analytics API tutorial we have seen how, starting from a GRID organization, it is possible to extract a) publications from authors associated to this organization, b) patents citing those publications (from any organization).
This only scratches the surface of the possible applications of publication-patents linkage data, but hopefully it’ll give you a few basic tools to get started building your own application. Here are some ideas for customizing this notebook:
Change the GRID ID to another one you are more familiar with
Use a different way to select publications: e.g. not using an organizations segment, but a category, a country, a funder or a combination of the many Publication filters available
Do a more in-depth analysis of the patents inventors: do they have other publications linking to the publications they cite in patents? Are there patterns of collaborations with the institutions they cite?
Note
The Dimensions Analytics API allows to carry out sophisticated research data analytics tasks like the ones described on this website. Check out also the associated Github repository for examples, the source code of these tutorials and much more.