You can run the walkthrough Python notebook in Google Colab with a single click:
Developed by Fast Data Science, https://fastdatascience.com
Source code at https://github.com/fastdatascience/drug_named_entity_recognition
Tutorial at https://fastdatascience.com/drug-named-entity-recognition-python-library/
This is a lightweight Python natural language processing library for finding drug names in a string, otherwise known as named entity recognition (NER) and named entity linking. This can be used for analysing unstructured text documents such as clinical trial protocols or other unstructured data in biopharma.
Please note this library finds only high confidence drugs.
New in version 2.0.0: we can support misspellings by using fuzzy matching!
It also only finds the English names of these drugs. Names in other languages are not supported.
It also doesn't find short code names of drugs, such as abbreviations commonly used in medicine, such as "Ceph" for "Cephradin" - as these are highly ambiguous.
You can install Drug Named Entity Recognition from PyPI.
pip install drug-named-entity-recognition
If you get an error installing Drug Named Entity Recognition, try making a new Python environment in Conda (conda create -n test-env; conda activate test-env
) or Venv (python -m testenv; source testenv/bin/activate
/ testenv\Scripts\activate
) and then installing the library.
The library already contains the drug names so if you don't need to update the dictionary, then you should not have to run any of the download scripts.
If you have problems installing, try our Google Colab walkthrough.
Check out our new Medical Named Entity Recognition package, now in beta! https://github.com/fastdatascience/medical_named_entity_recognition
You must first tokenise your input text using a tokeniser of your choice (NLTK, spaCy, etc).
You pass a list of strings to the find_drugs
function.
Example 1
from drug_named_entity_recognition import find_drugs
find_drugs("i bought some Prednisone".split(" "))
outputs a list of tuples.
[({'name': 'Prednisone', 'synonyms': {'Sone', 'Sterapred', 'Deltasone', 'Panafcort', 'Prednidib', 'Cortan', 'Rectodelt', 'Prednisone', 'Cutason', 'Meticorten', 'Panasol', 'Enkortolon', 'Ultracorten', 'Decortin', 'Orasone', 'Winpred', 'Dehydrocortisone', 'Dacortin', 'Cortancyl', 'Encorton', 'Encortone', 'Decortisyl', 'Kortancyl', 'Pronisone', 'Prednisona', 'Predniment', 'Prednisonum', 'Rayos'}, 'medline_plus_id': 'a601102', 'mesh_id': 'D018931', 'drugbank_id': 'DB00635'}, 3, 3)]
You can turn on fuzzy matching (ngrams) with is_fuzzy_match
find_drugs(["paraxcetamol"], is_fuzzy_match=True)
You can retrieve molecular structure in .mol
format with:
from drug_named_entity_recognition.drugs_finder import find_drugs
drugs = find_drugs("i bought some paracetamol".split(" "), is_include_structure=True)
this will return the atomic structure of the drug if that data is available.
>>> print (drugs[0][0]["structure_mol"])
316
Mrv0541 02231214352D
11 11 0 0 0 0 999 V2000
2.3645 -2.1409 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0
3.7934 1.1591 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0
2.3645 1.1591 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0
2.3645 0.3341 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
3.0790 -0.0784 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
1.6500 -0.0784 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
3.0790 -0.9034 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
1.6500 -0.9034 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
2.3645 -1.3159 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
3.0790 1.5716 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
3.0790 2.3966 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
1 9 1 0 0 0 0
2 10 2 0 0 0 0
3 4 1 0 0 0 0
3 10 1 0 0 0 0
4 5 2 0 0 0 0
4 6 1 0 0 0 0
5 7 1 0 0 0 0
6 8 2 0 0 0 0
7 9 2 0 0 0 0
8 9 1 0 0 0 0
10 11 1 0 0 0 0
M END
DB00316
Now you can modify the drug recogniser's behaviour if there is a particular drug which it isn't finding:
To reset the drugs dictionary
from drug_named_entity_recognition.drugs_finder import reset_drugs_data
reset_drugs_data()
To add a synonym
from drug_named_entity_recognition.drugs_finder import add_custom_drug_synonym
add_custom_drug_synonym("potato", "sertraline")
To add a new drug
from drug_named_entity_recognition.drugs_finder import add_custom_new_drug
add_custom_new_drug("potato", {"name": "solanum tuberosum"})
To remove an existing drug
from drug_named_entity_recognition.drugs_finder import remove_drug_synonym
remove_drug_synonym("sertraline")
If your NER problem is common across industries and likely to have been seen before, there may be an off-the-shelf NER tool for your purposes, such as our Country Named Entity Recognition Python library. Dictionary-based named entity recognition is not always the solution, as sometimes the total set of entities is an open set and can't be listed (e.g. personal names), so sometimes a bespoke trained NER model is the answer. For tasks like finding email addresses or phone numbers, regular expressions (simple rules) are sufficient for the job.
If your named entity recognition or named entity linking problem is very niche and unusual, and a product exists for that problem, that product is likely to only solve your problem 80% of the way, and you will have more work trying to fix the final mile than if you had done the whole thing manually. Please contact Fast Data Science and we'll be glad to discuss. For example, we've worked on a consultancy engagement to find molecule names in papers, and match author names to customers where the goal was to trace molecule samples ordered from a pharma company and identify when the samples resulted in a publication. For this case, there was no off-the-shelf library that we could use.
For a problem like identifying country names in English, which is a closed set with well-known variants and aliases, an off-the-shelf library is usually available. You may wish to try our Country Named Entity Recognition library, also open-source and under MIT license.
For identifying a set of molecules manufactured by a particular company, this is the kind of task more suited to a consulting engagement.
We have a no-code solution where you can use the library directly from Google Sheets as the library has also been wrapped as a Google Sheets plugin.
Click here to watch a video of how the plugin works.
You can install the plugin in Google Sheets here.
Python 3.9 and above
You can contact Thomas Wood or the Fast Data Science team at https://fastdatascience.com/.
The Drug Named Entity Recognition library is independent of other NLP tools and has no dependencies. You don't need any advanced system requirements and the tool is lightweight. However, it combines well with other libraries such as spaCy or the Natural Language Toolkit (NLTK).
Here is an example call to the tool with a spaCy Doc object:
from drug_named_entity_recognition import find_drugs
import spacy
nlp = spacy.blank("en")
doc = nlp("i routinely rx rimonabant and pts prefer it")
find_drugs([t.text for t in doc])
outputs:
[({'name': 'Rimonabant', 'synonyms': {'Acomplia', 'Rimonabant', 'Zimulti'}, 'mesh_id': 'D063387', 'drugbank_id': 'DB06155'}, 3, 3)]
You can also use the tool together with the Natural Language Toolkit (NLTK):
from drug_named_entity_recognition import find_drugs
from nltk.tokenize import wordpunct_tokenize
tokens = wordpunct_tokenize("i routinely rx rimonabant and pts prefer it")
find_drugs(tokens)
The main data source is from Drugbank, augmented by datasets from the NHS, MeSH, Medline Plus and Wikipedia.
🌟 There is a handy Jupyter Notebook, update.ipynb
which will update the Drugbank and MeSH data sources (re-download them from the relevant third parties).
If you want to update the dictionary, you can use the data dump from Drugbank and replace the file drugbank vocabulary.csv
:
If you want to update the Wikipedia dictionary, download the dump from:
and run extract_drug_names_and_synonyms_from_wikipedia_dump.py
If you want to update the dictionary, run
python download_mesh_dump_and_extract_drug_names_and_synonyms.py
This will download the latest XML file from NIH.
If the link doesn't work, download the open data dump manually from https://www.nlm.nih.gov/. It should be called something like desc2023.xml
. And comment out the Wget/Curl commands in the code.
To the extent possible under law, the person who associated CC0 with the DrugBank Open Data has waived all copyright and related or neighboring rights to the DrugBank Open Data. This work is published from: Canada.
If you'd like to contribute to this project, you can contact us at https://fastdatascience.com/ or make a pull request on our Github repository. You can also raise an issue.
Test code is in tests/ folder using unittest.
The testing tool tox
is used in the automation with GitHub Actions CI/CD.
Install tox and run it:
pip install tox
tox
In our configuration, tox runs a check of source distribution using check-manifest (which requires your repo to be git-initialized (git init
) and added (git add .
) at least), setuptools's check, and unit tests using pytest. You don't need to install check-manifest and pytest though, tox will install them in a separate environment.
The automated tests are run against several Python versions, but on your machine, you might be using only one version of Python, if that is Python 3.9, then run:
tox -e py39
Thanks to GitHub Actions' automated process, you don't need to generate distribution files locally. But if you insist, click to read the "Generate distribution files" section.
This package is based on the template https://pypi.org/project/example-pypi-package/
This package
master
or main
branch, and is published when create a releaseThe code to re-release Drug Named Entity Recognition on PyPI is as follows:
source activate py311
pip install twine
rm -rf dist
python setup.py sdist
twine upload dist/*
The tool was developed by:
MIT License. Copyright (c) 2023 Fast Data Science
Wood, T.A., Drug Named Entity Recognition [Computer software], Version 2.0.5, accessed at https://fastdatascience.com/drug-named-entity-recognition-python-library, Fast Data Science Ltd (2024)
@unpublished{drugnamedentityrecognition,
AUTHOR = {Wood, T.A.},
TITLE = {Drug Named Entity Recognition (Computer software), Version 2.0.5},
YEAR = {2024},
Note = {To appear},
url = {https://zenodo.org/doi/10.5281/zenodo.10970631},
doi = {10.5281/zenodo.10970631}
}