Construire un graphique de connaissances biomédicales avec la PNL

Nœud source: 1401511

J'ai déjà montré comment créer un graphe de connaissances à partir d'une page Wikipédia. Cependant, comme le message a attiré beaucoup d'attention, j'ai décidé d'explorer d'autres domaines où l'utilisation de techniques de PNL pour construire un graphe de connaissances a du sens. À mon avis, le domaine biomédical est un excellent exemple où la représentation des données sous forme de graphique a du sens car vous analysez souvent les interactions et les relations entre les gènes, les maladies, les médicaments, les protéines, etc.

Exemple de sous-graphique montrant les relations entre l'acide ascorbique et d'autres concepts biomédicaux. Image de l'auteur.

Dans la visualisation ci-dessus, nous avons l'acide ascorbique, également connu sous le nom de vitamine C, et certaines de ses relations avec d'autres concepts. Par exemple, il montre que la vitamine C pourrait être utilisée pour traiter la gastrite chronique.

Maintenant, vous pouvez demander à une équipe d'experts du domaine de cartographier pour vous tous ces liens entre les médicaments, les maladies et d'autres concepts biomédicaux. Mais, malheureusement, peu d'entre nous peuvent se permettre d'embaucher une équipe de médecins pour faire le travail à notre place. Dans ce cas, nous pouvons recourir à l'utilisation de techniques NLP pour extraire automatiquement ces relations. La bonne partie est que nous pouvons utiliser un pipeline NLP pour lire tous les articles de recherche disponibles, et la mauvaise partie est que tous les résultats obtenus ne seront pas parfaits. Cependant, étant donné que je n'ai pas d'équipe de scientifiques prêts à mes côtés pour extraire manuellement les relations, je vais recourir à l'utilisation de techniques de PNL pour construire mon propre graphe de connaissances biomédicales.

J'utiliserai un seul article de recherche dans cet article de blog pour vous guider à travers toutes les étapes nécessaires à la construction d'un graphe de connaissances biomédicales - Ingénierie tissulaire de la régénération de la peau et de la croissance des cheveux.

Le papier a été écrit par Mohammadreza Ahmadi. La version PDF de l'article est disponible sous la licence CC0 1.0. Nous allons passer par les étapes suivantes pour construire un graphe de connaissances :

  • Lire un document PDF avec OCR
  • Prétraitement de texte
  • Reconnaissance et mise en relation des concepts biomédicaux
  • Extraction de relations
  • Enrichissement de la base de données externe

À la fin de cet article, vous construirez un graphique avec le schéma suivant.

Schéma graphique biomédical. Image de l'auteur.

Nous utiliserons Neo4j, une base de données de graphes qui présente le modèle de graphe de propriétés étiquetées, pour stocker notre graphe. Chaque article peut avoir un ou plusieurs auteurs. Nous diviserons le contenu de l'article en phrases et utiliserons la PNL pour extraire à la fois les entités médicales et leurs relations. Il pourrait être un peu contre-intuitif que nous stockions les relations entre les entités en tant que nœuds intermédiaires au lieu de relations. Le facteur critique derrière cette décision est que nous voulons avoir une piste d'audit du texte source à partir duquel la relation a été extraite. Avec le modèle de graphe de propriétés étiqueté, vous ne pouvez pas avoir une relation pointant vers une autre relation. Pour cette raison, nous refactorisons la connexion entre les concepts médicaux en un nœud intermédiaire. Cela permettra également à un expert du domaine d'évaluer si une relation a été correctement extraite ou non.

En cours de route, je démontrerai également des applications de l'utilisation du graphe construit pour rechercher et analyser des informations stockées.

Plongeons dedans!

Si ce contenu éducatif approfondi vous est utile, abonnez-vous à notre liste de diffusion de recherche sur l'IA d'être alerté lorsque nous publierons du nouveau matériel.

Lire un document PDF avec OCR

Comme mentionné, la version PDF du document de recherche est accessible au public sous la licence CC0 1.0, ce qui signifie que nous pouvons facilement la télécharger avec Python. Nous utiliserons le pytesseract bibliothèque pour extraire le texte du PDF. Autant que je sache, la bibliothèque pytesseract est l'une des bibliothèques les plus populaires pour l'OCR. Si vous souhaitez suivre des exemples de code, j'ai préparé un Bloc-notes Google Colab, vous n'avez donc pas à copier-coller le code vous-même.

import requests
import pdf2image
import pytesseract pdf = requests.get('https://arxiv.org/pdf/2110.03526.pdf')
doc = pdf2image.convert_from_bytes(pdf.content) # Get the article text
article = []
for page_number, page_data in enumerate(doc): txt = pytesseract.image_to_string(page_data).encode("utf-8") # Sixth page are only references if page_number < 6: article.append(txt.decode("utf-8"))
article_txt = " ".join(article)

Prétraitement de texte

Maintenant que nous avons le contenu de l'article disponible, nous allons continuer et supprimer les titres de section et les descriptions des figures du texte. Ensuite, nous allons diviser le texte en phrases.

import nltk
nltk.download('punkt') def clean_text(text): """Remove section titles and figure descriptions from text""" clean = "n".join([row for row in text.split("n") if (len(row.split(" "))) > 3 and not (row.startswith("(a)")) and not row.startswith("Figure")]) return clean text = article_txt.split("INTRODUCTION")[1]
ctext = clean_text(text)
sentences = nltk.tokenize.sent_tokenize(ctext)

Liaison d'entités nommées biomédicales

Vient maintenant la partie passionnante. Pour ceux qui découvrent la PNL et la reconnaissance et la liaison d'entités nommées, commençons par quelques notions de base. Des techniques de reconnaissance d'entités nommées sont utilisées pour détecter des entités ou des concepts pertinents dans le texte. Par exemple, dans le domaine biomédical, nous voulons identifier divers gènes, médicaments, maladies et autres concepts dans le texte.

Extraction de concepts biomédicaux. Image de l'auteur.

Dans cet exemple, le modèle PNL a identifié des gènes, des maladies, des médicaments, des espèces, des mutations et des voies dans le texte. Comme mentionné, ce processus est appelé reconnaissance d'entité nommée. Une mise à niveau vers la reconnaissance d'entités nommées est ce que l'on appelle la liaison d'entités nommées. La technique de liaison d'entités nommées détecte les concepts pertinents dans le texte et tente de les mapper à la base de connaissances cible. Dans le domaine biomédical, certaines des bases de connaissances ciblées sont :

Pourquoi voudrions-nous lier des entités médicales à une base de connaissances ciblée ? La principale raison est que cela nous aide à gérer la désambiguïsation des entités. Par exemple, nous ne voulons pas d'entités distinctes dans le graphique représentant l'acide ascorbique et la vitamine C, car les experts du domaine peuvent vous dire que c'est la même chose. La raison secondaire est qu'en mappant des concepts à une base de connaissances cible, nous pouvons enrichir notre modèle de graphe en récupérant des informations sur les concepts mappés à partir de la base de connaissances cible. Si nous utilisons à nouveau l'exemple de l'acide ascorbique, nous pourrions facilement récupérer des informations supplémentaires dans la base de données CHEBI si nous connaissons déjà son Identifiant CHEBI.

Données d'enrichissement disponibles sur l'acide ascorbique sur le site CHEBI. Tout le contenu du site est disponible sous Licence CC BY 4.0. Image de l'auteur.

Je cherchais depuis un certain temps une entité nommée biomédicale pré-formée et open-source décente. De nombreux modèles de PNL se concentrent sur l'extraction d'un sous-ensemble spécifique de concepts médicaux tels que les gènes ou les maladies. Il est encore plus rare de trouver un modèle qui détecte la plupart des concepts médicaux et les relie à une base de connaissances ciblée. Heureusement je suis tombé sur BERNE[1], un outil de reconnaissance et de normalisation multi-type d'entités biomédicales neurales. Si je comprends bien, il s'agit d'un modèle BioBert affiné avec divers modèles de liaison d'entités nommées intégrés pour mapper les concepts aux bases de connaissances biomédicales cibles. Non seulement cela, mais ils fournissent également un point de terminaison REST gratuit, nous n'avons donc pas à nous soucier de faire fonctionner les dépendances et le modèle. La visualisation biomédicale de reconnaissance d'entités nommées que j'ai utilisée ci-dessus a été créée à l'aide du modèle BERN, nous savons donc qu'elle détecte les gènes, les maladies, les médicaments, les espèces, les mutations et les voies dans le texte.

Malheureusement, le modèle BERN n'attribue pas d'identifiants de base de connaissances cibles à tous les concepts. J'ai donc préparé un script qui regarde d'abord si un identifiant distinct est donné pour un concept, et si ce n'est pas le cas, il utilisera le nom de l'entité comme identifiant. Nous calculerons également le sha256 du texte des phrases pour identifier plus facilement des phrases spécifiques plus tard lorsque nous ferons l'extraction de relations.

import hashlib def query_raw(text, url="https://bern.korea.ac.kr/plain"): """Biomedical entity linking API""" return requests.post(url, data={'sample_text': text}).json() entity_list = []
# The last sentence is invalid
for s in sentences[:-1]: entity_list.append(query_raw(s)) parsed_entities = []
for entities in entity_list: e = [] # If there are not entities in the text if not entities.get('denotations'): parsed_entities.append({'text':entities['text'], 'text_sha256': hashlib.sha256(entities['text'].encode('utf-8')).hexdigest()}) continue for entity in entities['denotations']: other_ids = [id for id in entity['id'] if not id.startswith("BERN")] entity_type = entity['obj'] entity_name = entities['text'][entity['span']['begin']:entity['span']['end']] try: entity_id = [id for id in entity['id'] if id.startswith("BERN")][0] except IndexError: entity_id = entity_name e.append({'entity_id': entity_id, 'other_ids': other_ids, 'entity_type': entity_type, 'entity': entity_name}) parsed_entities.append({'entities':e, 'text':entities['text'], 'text_sha256': hashlib.sha256(entities['text'].encode('utf-8')).hexdigest()})

J'ai inspecté les résultats de la liaison de l'entité nommée et, comme prévu, ce n'est pas parfait. Par exemple, il n'identifie pas les cellules souches comme un concept médical. En revanche, il a détecté une seule entité nommée "cœur, cerveau, nerfs et rein". Cependant, BERN reste le meilleur modèle biomédical open source que j'ai pu trouver au cours de mon enquête.

Construire un graphe de connaissances

Avant d'aborder les techniques d'extraction de relations, nous allons construire un graphe de connaissances biomédicales utilisant uniquement des entités et examiner les applications possibles. Comme mentionné, j'ai préparé un Bloc-notes Google Colab que vous pouvez utiliser pour suivre les exemples de code dans ce post. Pour stocker notre graphique, nous utiliserons Neo4j. Vous n'avez pas à vous soucier de la préparation d'un environnement Neo4j local. Au lieu de cela, vous pouvez utiliser une instance gratuite de Neo4j Sandbox.

Bac à sable Neo4j

Commencer le Projet vierge dans le bac à sable et copiez les détails de connexion dans le notebook Colab.

Détails de connexion à Neo4j Sandbox. Image de l'auteur.

Vous pouvez maintenant continuer et préparer la connexion Neo4j dans le notebook.

from neo4j import GraphDatabase
import pandas as pd host = 'bolt://3.236.182.55:7687'
user = 'neo4j'
password = 'hydrometer-ditches-windings'
driver = GraphDatabase.driver(host,auth=(user, password)) def neo4j_query(query, params=None): with driver.session() as session: result = session.run(query, params) return pd.DataFrame([r.values() for r in result], columns=result.keys())

Nous allons commencer par importer l'auteur et l'article dans le graphique. Le nœud de l'article ne contiendra que le titre.

author = article_txt.split("n")[0]
title = " ".join(article_txt.split("n")[2:4]) neo4j_query("""
MERGE (a:Author{name:$author})
MERGE (b:Article{title:$title})
MERGE (a)-[:WROTE]->(b)
""", {'title':title, 'author':author})

Si vous ouvrez le navigateur Neo4j, vous devriez voir le graphique suivant.

Image de l'auteur.

Vous pouvez importer les phrases et les entités mentionnées en exécutant la requête Cypher suivante :

neo4j_query("""
MATCH (a:Article)
UNWIND $data as row
MERGE (s:Sentence{id:row.text_sha256})
SET s.text = row.text
MERGE (a)-[:HAS_SENTENCE]->(s)
WITH s, row.entities as entities
UNWIND entities as entity
MERGE (e:Entity{id:entity.entity_id})
ON CREATE SET e.other_ids = entity.other_ids, e.name = entity.entity, e.type = entity.entity_type
MERGE (s)-[m:MENTIONS]->(e)
ON CREATE SET m.count = 1
ON MATCH SET m.count = m.count + 1
""", {'data': parsed_entities})

Vous pouvez exécuter la requête Cypher suivante pour inspecter le graphe construit :

MATCH p=(a:Article)-[:HAS_SENTENCE]->()-[:MENTIONS]->(e:Entity)
RETURN p LIMIT 25

Si vous avez correctement importé les données, vous devriez voir une visualisation similaire.

Extraction d'entités stockées sous forme de graphique. Image de l'auteur.

Applications du graphe de connaissances

Même sans le flux d'extraction de relation, il existe déjà quelques cas d'utilisation pour notre graphe.

Optimisation des

Nous pourrions utiliser notre graphique comme moteur de recherche. Par exemple, vous pouvez utiliser la requête Cypher suivante pour rechercher des phrases ou des articles qui mentionnent une entité médicale spécifique.

MATCH (e:Entity)<-[:MENTIONS]-(s:Sentence)
WHERE e.name = "autoimmune diseases"
RETURN s.text as result

Résultats

Image de l'auteur.

Analyse de cooccurrence

La deuxième option est l'analyse des cooccurrences. Vous pouvez définir la cooccurrence entre entités médicales si elles apparaissent dans la même phrase ou le même article. J'ai trouvé un article[2] qui utilise le réseau de cooccurrence médicale pour prédire de nouvelles connexions possibles entre entités médicales.

Prédiction de lien dans un réseau de cooccurrence MeSH : résultats préliminaires – PubMed

Vous pouvez utiliser la requête Cypher suivante pour rechercher des entités qui coexistent souvent dans la même phrase.

MATCH (e1:Entity)<-[:MENTIONS]-()-[:MENTIONS]->(e2:Entity)
MATCH (e1:Entity)<-[:MENTIONS]-()-[:MENTIONS]->(e2:Entity)
WHERE id(e1) < id(e2)
RETURN e1.name as entity1, e2.name as entity2, count(*) as cooccurrence
ORDER BY cooccurrence
DESC LIMIT 3

Résultats

entité1 entité2 coïncidence
maladies de la peau ulcères diabétiques 2
plaies chroniques ulcères diabétiques 2
maladies de la peau plaies chroniques 2

Évidemment, les résultats seraient meilleurs si nous analysions des milliers d'articles ou plus.

Inspecter l'expertise de l'auteur

Vous pouvez également utiliser ce graphique pour trouver l'expertise de l'auteur en examinant les entités médicales sur lesquelles il écrit le plus souvent. Avec ces informations, vous pourriez également suggérer de futures collaborations.

Exécutez la requête Cypher suivante pour inspecter les entités médicales que notre auteur unique a mentionnées dans le document de recherche.

MATCH (a:Author)-[:WROTE]->()-[:HAS_SENTENCE]->()-[:MENTIONS]->(e:Entity)
RETURN a.name as author, e.name as entity,
MATCH (a:Author)-[:WROTE]->()-[:HAS_SENTENCE]->()-[:MENTIONS]->(e:Entity)
RETURN a.name as author, e.name as entity, count(*) as count
ORDER BY count DESC
LIMIT 5

Résultats

auteur entité compter
Mohammadreza Ahmadi Collagène 9
Mohammadreza Ahmadi brûlures 4
Mohammadreza Ahmadi maladies de la peau 4
Mohammadreza Ahmadi enzymes collagénase 2
Mohammadreza Ahmadi Épidermolyse bulleuse 2

Extraction de relations

Nous allons maintenant essayer d'extraire les relations entre les concepts médicaux. D'après mon expérience, l'extraction de relation est au moins d'un ordre de grandeur plus difficile que l'extraction d'entité nommée. Si vous ne devez pas vous attendre à des résultats parfaits avec la liaison d'entités nommées, vous pouvez certainement vous attendre à des erreurs avec la technique d'extraction de relation.

J'ai cherché des modèles d'extraction de relations biomédicales disponibles, mais je n'ai rien trouvé qui fonctionne immédiatement ou qui ne nécessite pas d'ajustements. Il semble que le domaine de l'extraction de relations soit à la pointe, et j'espère que nous y verrons plus d'attention à l'avenir. Malheureusement, je ne suis pas un expert en PNL, j'ai donc évité de peaufiner mon propre modèle. Au lieu de cela, nous utiliserons l'extracteur de relation zéro-coup basé sur le papier Explorer la limite de tir zéro de FewRel[3]. Bien que je ne recommande pas de mettre ce modèle en production, il est suffisant pour une simple démonstration. Le modèle est disponible sur Étreindre, nous n'avons donc pas à nous occuper de la formation ou de la configuration du modèle.

from transformers import AutoTokenizer
from zero_shot_re import RelTaggerModel, RelationExtractor model = RelTaggerModel.from_pretrained("fractalego/fewrel-zero-shot")
tokenizer = AutoTokenizer.from_pretrained("bert-large-uncased-whole-word-masking-finetuned-squad")
relations = ['associated', 'interacts']
extractor = RelationExtractor(model, tokenizer, relations)

Avec l'extracteur de relation zéro-shot, vous pouvez définir les relations que vous souhaitez détecter. Dans cet exemple, j'ai utilisé le associé ainsi que  interagit des relations. J'ai également essayé des types de relations plus spécifiques tels que des friandises, des causes et autres, mais les résultats n'étaient pas excellents.

Avec ce modèle, vous devez définir entre quelles paires d'entités vous souhaitez détecter des relations. Nous utiliserons les résultats de la liaison d'entité nommée comme entrée du processus d'extraction de relation. Tout d'abord, nous trouvons toutes les phrases où deux entités ou plus sont mentionnées, puis nous les analysons dans le modèle d'extraction de relations pour extraire toutes les connexions. J'ai également défini une valeur seuil de 0.85, ce qui signifie que si un modèle prédit un lien entre des entités avec une probabilité inférieure à 0.85, nous ignorerons la prédiction.

import itertools
# Candidate sentence where there is more than a single entity present
candidates = [s for s in parsed_entities if (s.get('entities')) and (len(s['entities']) &gt; 1)]
predicted_rels = []
for c in candidates: combinations = itertools.combinations([{'name':x['entity'], 'id':x['entity_id']} for x in c['entities']], 2) for combination in list(combinations): try: ranked_rels = extractor.rank(text=c['text'].replace(",", " "), head=combination[0]['name'], tail=combination[1]['name']) # Define threshold for the most probable relation if ranked_rels[0][1] &gt; 0.85: predicted_rels.append({'head': combination[0]['id'], 'tail': combination[1]['id'], 'type':ranked_rels[0][0], 'source': c['text_sha256']}) except: pass # Store relations to Neo4j
neo4j_query("""
UNWIND $data as row
MATCH (source:Entity {id: row.head})
MATCH (target:Entity {id: row.tail})
MATCH (text:Sentence {id: row.source})
MERGE (source)-[:REL]-&gt;(r:Relation {type: row.type})-[:REL]-&gt;(target)
MERGE (text)-[:MENTIONS]-&gt;(r)
""", {'data': predicted_rels})

Nous stockons les relations ainsi que le texte source utilisé pour extraire cette relation dans le graphique.

Relations extraites stockées dans un graphe. Image de l'auteur.

Vous pouvez examiner les relations extraites entre les entités et le texte source avec la requête Cypher suivante :

MATCH (s:Entity)-[:REL]->(r:Relation)-[:REL]->(t:Entity), (r)<-[:MENTIONS]-(st:Sentence)
RETURN s.name as source_entity, t.name as target_entity, r.type as type, st.text as source_text

Résultats

Image de l'auteur.

Comme mentionné, le modèle PNL que j'ai utilisé pour extraire les relations n'est pas parfait, et comme je ne suis pas médecin, je ne sais pas combien de connexions il a manqué. Cependant, ceux qu'il a détectés semblent raisonnables.

Enrichissement de la base de données externe

Comme je l'ai mentionné précédemment, nous pouvons toujours utiliser les bases de données externes comme CHEBI ou MESH pour enrichir notre graphique. Par exemple, notre graphique contient une entité médicale Épidermolyse bulleuse et nous connaissons également son identifiant MeSH.

Vous pouvez récupérer l'identifiant MeSH de l'épidermolyse bulleuse avec la requête suivante :

MATCH (e:Entity)
WHERE e.name = "Epidermolysis bullosa"
RETURN e.name as entity, e.other_ids as other_ids

Vous pouvez aller de l'avant et inspecter le MeSH pour trouver les informations disponibles :

Données liées MeSH

Capture d'écran par l'auteur. Les données sont fournies avec l'aimable autorisation de la National Library of Medicine des États-Unis.

Voici une capture d'écran des informations disponibles sur le site MeSH pour l'épidermolyse bulleuse. Comme mentionné, je ne suis pas médecin, donc je ne sais pas exactement quelle serait la meilleure façon de modéliser ces informations dans un graphique. Cependant, je vais vous montrer comment récupérer ces informations dans Neo4j en utilisant la procédure apoc.load.json pour récupérer les informations du point de terminaison MeSH REST. Et ensuite, vous pouvez demander à un expert du domaine de vous aider à modéliser ces informations.

La requête Cypher pour récupérer les informations du point de terminaison MeSH REST est :

MATCH (e:Entity)
WHERE e.name = "Epidermolysis bullosa"
WITH e, [id in e.other_ids WHERE id contains "MESH" | split(id,":")[1]][0] as meshId
CALL apoc.load.json("https://id.nlm.nih.gov/mesh/lookup/details?descriptor=" + meshId) YIELD value
RETURN value

Graphe de connaissances en tant qu'entrée de données d'apprentissage automatique

Pour finir, je vais vous expliquer rapidement comment vous pouvez utiliser le graphe de connaissances biomédicales comme entrée d'un flux de travail d'apprentissage automatique. Ces dernières années, il y a eu beaucoup de recherches et de progrès dans le domaine de l'intégration de nœuds. Les modèles d'intégration de nœuds traduisent la topologie du réseau en espace d'intégration.

Copyright © 2017 Manan Shah, groupe SNAP. Image disponible sous licence MIT en https://github.com/snap-stanford/cs224w-notes.

Supposons que vous construisiez un graphe de connaissances biomédicales contenant des entités et des concepts médicaux, leurs relations et un enrichissement à partir de diverses bases de données médicales. Vous pouvez utiliser des techniques d'intégration de nœuds pour apprendre les représentations de nœuds, qui sont des vecteurs de longueur fixe, et les entrer dans votre flux de travail d'apprentissage automatique. Diverses applications utilisent cette approche, allant de la réorientation des médicaments aux prédictions des effets secondaires ou indésirables des médicaments. J'ai trouvé un document de recherche qui utilise prédiction de liens pour les traitements potentiels de nouvelles maladies[4].

Conclusion

Le domaine biomédical est un excellent exemple où les graphes de connaissances sont applicables. Il existe de nombreuses applications allant des moteurs de recherche simples aux flux de travail d'apprentissage automatique plus complexes. J'espère qu'en lisant ce billet de blog, vous avez trouvé des idées sur la façon dont vous pourriez utiliser les graphiques de connaissances biomédicales pour soutenir vos applications. Vous pouvez démarrer une Bac à sable Neo4j gratuit et commencez à explorer dès aujourd'hui.

Comme toujours, le code est disponible sur GitHub.

Bibliographie

[1] D.Kim et al., "Un outil de reconnaissance d'entités nommées neurales et de normalisation multi-types pour l'exploration de texte biomédical", dans Accès IEEE, vol. 7, pages 73729–73740, 2019, doi : 10.1109/ACCESS.2019.2920708.

[2] Kastrin A, Rindflesch TC, Hristovski D. Prédiction de liens dans un réseau de cooccurrence MeSH : résultats préliminaires. Stud Health Technol Inform. 2014 ;205 : 579–83. PMID : 25160252.

[3] Cetoli, A. (2020). Explorer la limite de tir zéro de FewRel. Dans Actes de la 28e Conférence internationale sur la linguistique computationnelle (pp. 1447–1451). Comité international de linguistique computationnelle.

[4] Zhang, R., Hristovski, D., Schutte, D., Kastrin, A., Fiszman, M. et Kilicoglu, H. (2021). Réorientation des médicaments pour le COVID-19 via l'achèvement du graphe de connaissances. Journal d'informatique biomédicale, 115, 103696.

Cet article a été publié initialement le Vers la science des données et republié sur TOPBOTS avec la permission de l'auteur.

Profitez de cet article? Inscrivez-vous pour plus de mises à jour de l'IA.

Nous vous informerons lorsque nous publierons plus de formation technique.

Le poste Construire un graphique de connaissances biomédicales avec la PNL apparaît en premier sur TOPBOTS.

Horodatage:

Plus de TOPBOTS