Fermer

décembre 19, 2023

Comment analyser de grands ensembles de données textuelles avec LangChain et Python

Comment analyser de grands ensembles de données textuelles avec LangChain et Python


Dans ce didacticiel, nous allons explorer comment analyser de grands ensembles de données textuelles avec LangChain et Python pour trouver des données intéressantes dans n’importe quoi, des livres aux pages Wikipédia.

L’IA est un sujet tellement important de nos jours qu’OpenAI et des bibliothèques comme LangChain n’ont pratiquement pas besoin d’être présentées. Néanmoins, au cas où vous seriez perdu dans une dimension alternative au cours de la dernière année, LangChaîneen un mot, est un cadre de développement d’applications alimentées par des modèles de langage, permettant aux développeurs d’utiliser la puissance des LLM et de l’IA pour analyser les données et créer leurs propres applications d’IA.

Table des matières

Cas d’utilisation

Avant d’entrer dans tous les détails techniques, je pense qu’il est bon d’examiner quelques cas d’utilisation de l’analyse d’ensembles de données textuelles à l’aide de LangChain. Voici quelques exemples:

  • Extraire systématiquement les données utiles de documents longs.
  • Visualiser les tendances dans un texte ou un ensemble de données textuelles.
  • Faire des résumés de textes longs et sans intérêt.

Conditions préalables

Pour suivre cet article, créez un nouveau dossier et installez LangChain et OpenAI à l’aide de pip :

pip3 install langchain openai

Lecture de fichiers, fractionnement de texte et extraction de données

Pour analyser des textes volumineux, tels que des livres, vous devez diviser les textes en morceaux plus petits. En effet, les textes volumineux, tels que les livres, contiennent des centaines de milliers, voire des millions de jetons, et étant donné qu’aucun LLM ne peut traiter autant de jetons à la fois, il n’y a aucun moyen d’analyser ces textes dans leur ensemble sans les diviser.

De plus, au lieu d’enregistrer les sorties d’invite individuelles pour chaque morceau de texte, il est plus efficace d’utiliser un modèle pour extraire les données et les mettre dans un format tel que JSON ou CSV.

Dans ce tutoriel, j’utiliserai JSON. Voici le livre que j’utilise pour cet exempleque j’ai téléchargé gratuitement depuis le projet Gutenberg. Ce code lit le livre Au-delà du Bien et du Mal de Friedrich Nietzsche, le divise en chapitres, fait un résumé du premier chapitre, extrait les messages philosophiques, les théories éthiques et les principes moraux présentés dans le texte, et met le tout au format JSON.

Comme vous pouvez le voir, j’ai utilisé le modèle « gpt-3.5-turbo-1106 » pour travailler avec des contextes plus larges allant jusqu’à 16 000 jetons et une température de 0,3 pour lui donner un peu de créativité. Vous pouvez expérimenter avec la température et voir ce qui fonctionne le mieux avec votre cas d’utilisation.

Noter la temperature Ce paramètre détermine la liberté d’un LLM de formuler des réponses créatives et parfois aléatoires. Plus la température est basse, plus la sortie LLM est factuelle, et plus la température est élevée, plus la sortie LLM est créative et aléatoire.

Les données extraites sont mises au format JSON en utilisant create_structured_output_chain et le schéma JSON fourni :

json_schema = {
    "type": "object",
    "properties": {
        "summary": {"title": "Summary", "description": "The chapter summary", "type": "string"},
        "messages": {"title": "Messages", "description": "Philosophical messages", "type": "string"},
        "ethics": {"title": "Ethics", "description": "Ethical theories and moral principles presented in the text", "type": "string"}
    },
    "required": ["summary", "messages", "ethics"],
}

chain = create_structured_output_chain(json_schema, llm, prompt, verbose=False)

Le code lit ensuite le fichier texte contenant le livre et le divise par chapitre. La chaîne reçoit ensuite le premier chapitre du livre sous forme de texte :

f = open("texts/Beyond Good and Evil.txt", "r")
phi_text = str(f.read())
chapters = phi_text.split("CHAPTER")
print(chain.run(chapters[1]))

Voici le résultat du code :

{'summary': 'The chapter discusses the concept of utilitarianism and its application in ethical decision-making. It explores the idea of maximizing overall happiness and minimizing suffering as a moral principle. The chapter also delves into the criticisms of utilitarianism and the challenges of applying it in real-world scenarios.', 'messages': 'The chapter emphasizes the importance of considering the consequences of our actions and the well-being of all individuals affected. It encourages thoughtful and empathetic decision-making, taking into account the broader impact on society.', 'ethics': 'The ethical theories presented in the text include consequentialism, hedonistic utilitarianism, and the principle of the greatest good for the greatest number.'}

Plutôt cool. Les textes philosophiques écrits il y a 150 ans sont assez difficiles à lire et à comprendre, mais ce code traduit instantanément les points principaux du premier chapitre en un rapport facile à comprendre du résumé, du message et des théories éthiques/principes moraux du chapitre. L’organigramme ci-dessous vous donnera une représentation visuelle de ce qui se passe dans ce code.

Organigramme du fonctionnement du code avec un seul chapitre

Vous pouvez maintenant faire la même chose pour tous les chapitres et tout mettre dans un fichier JSON en utilisant ce code.

J’ai ajouté time.sleep(20) comme commentaires, car il est possible que vous atteigniez les limites de débit lorsque vous travaillez avec des textes volumineux, probablement si vous disposez du niveau gratuit de l’API OpenAI. Puisque je pense qu’il est pratique de savoir combien de jetons et de crédits vous utilisez avec vos demandes afin de ne pas vider accidentellement votre compte, j’ai également utilisé with get_openai_callback() as cb: pour voir combien de jetons et de crédits sont utilisés pour chaque chapitre.

Il s’agit de la partie du code qui analyse chaque chapitre et place les données extraites pour chacun dans un fichier JSON partagé :

for chi in range(1, len(chapters), 1):
    with get_openai_callback() as cb:
        ch = chain.run(chapters[chi])
        print(cb)
        print("\n")

    print(ch)
    print("\n\n")
    json_object = json.dumps(ch, indent=4)

    if chi == 1:
        with open("Beyond Good and Evil.json", "w") as outfile:
            outfile.write("[\n"+json_object+",")
    elif chi < len(chapters)-1:
        with open("Beyond Good and Evil.json", "a") as outfile:
            outfile.write(json_object+",")
    else:
        with open("Beyond Good and Evil.json", "a") as outfile:
            outfile.write(json_object+"\n]")

Le chi l’index commence à 1, car il n’y a pas de chapitre 0 avant le chapitre 1. Si le chi l’index est 1 (sur le premier chapitre), le code écrit (écrase tout contenu existant) les données JSON dans le fichier tout en ajoutant également un crochet ouvrant et une nouvelle ligne au début, et une virgule à la fin pour suivre la syntaxe JSON. Si chi n’est pas la valeur minimale (1) ou la valeur maximale (len(chapters)-1), les données JSON sont simplement ajoutées au fichier avec une virgule à la fin. Enfin, si chi est à sa valeur maximale, le JSON est ajouté au fichier JSON avec une nouvelle ligne et un crochet fermant.

Une fois l’exécution du code terminée, vous verrez que Beyond Good and Evil.json est rempli des informations extraites de tous les chapitres.

Fichier JSON rempli de données extraites des chapitres

Voici une représentation visuelle du fonctionnement de ce code.

Organigramme du fonctionnement du code avec plusieurs chapitres

Travailler avec plusieurs fichiers

Si vous avez des dizaines de fichiers distincts que vous souhaitez analyser un par un, vous pouvez utiliser un script similaire à celui que vous venez de voir, mais au lieu de parcourir les chapitres, il parcourra les fichiers d’un dossier.

J’utiliserai l’exemple d’un dossier rempli d’articles Wikipédia sur les 10 meilleurs joueurs de tennis classés (au 3 décembre 2023) appelé top_10_tennis_players. Vous pouvez télécharger le dossier ici. Ce code lira chaque article Wikipédia, extraira l’âge, la taille et le service le plus rapide de chaque joueur en km/h et placera les données extraites dans un fichier JSON dans un dossier séparé appelé player_data.

Voici un exemple de fichier de données de joueur extrait.

Daniil Medvedev a extrait les données

Cependant, ce code n’est pas si simple (j’aurais aimé qu’il le soit). Pour extraire de manière efficace et fiable les données les plus précises de textes souvent trop volumineux pour être analysés sans fractionnement, j’ai utilisé ce code :

from langchain.text_splitter import RecursiveCharacterTextSplitter
text_splitter = RecursiveCharacterTextSplitter(
    chunk_size=16000,
    chunk_overlap=2000,
    length_function=len,
    add_start_index=True,
)
sub_texts = text_splitter.create_documents([player_text])
ch = []
for ti in range(len(sub_texts)):
    with get_openai_callback() as cb:
        ch.append(chain.run(sub_texts[ti]))
        print(ch[-1])
        print(cb)
        print("\n")
        

    for chi in range(1, len(ch), 1):
        if (ch[chi]["age"] > ch[0]["age"]) or (ch[0]["age"] == "not found" and ch[chi]["age"] != "not found"):
            ch[0]["age"] = ch[chi]["age"]
            break
        if (ch[chi]["serve"] > ch[0]["serve"]) or (ch[0]["serve"] == "not found" and ch[chi]["serve"] != "not found"):
            ch[0]["serve"] = ch[chi]["serve"]
            break
        if (ch[0]["height"] == "not found") and (ch[chi]["height"] != "not found"):
            ch[0]["height"] = ch[chi]["height"]
            break
        else:
            continue

Essentiellement, ce code fait ce qui suit :

  1. Il divise le texte en morceaux d’une taille de 16 000 jetons, avec un chevauchement de morceaux de 2 000 pour conserver un peu de contexte.
  2. il extrait les données spécifiées de chaque morceau.
  3. Si les données extraites du dernier fragment sont plus pertinentes ou plus précises que celles du premier fragment (ou si la valeur n’est pas trouvée dans le premier fragment mais se trouve dans le dernier fragment), il ajuste les valeurs du premier fragment. Par exemple, si le morceau 1 dit 'age': 26 et le morceau 2 dit 'age': 27le age la valeur sera mise à jour à 27 puisque nous avons besoin du dernier âge du joueur, ou si le morceau 1 indique 'serve': 231 et le morceau 2 dit 'serve': 232le serve la valeur sera mise à jour à 232 puisque nous recherchons la vitesse de service la plus rapide.

Voici comment l’ensemble du code fonctionne dans un organigramme.

Organigramme de la façon dont le code fonctionne avec plusieurs fichiers et morceaux

Texte vers intégrations

Intégrations sont des listes vectorielles utilisées pour associer des morceaux de texte les uns aux autres.

Un aspect important de l’analyse de texte dans LangChain consiste à rechercher dans des textes volumineux des morceaux spécifiques pertinents pour une certaine entrée ou question.

On peut reprendre l’exemple avec le Au-delà du Bien et du Mal livre de Friedrich Nietzsche et créez un script simple qui répond à une question sur le texte comme « Quels sont les défauts des philosophes ? », le transforme en intégration, divise le livre en chapitres, transforme les différents chapitres en intégrations et trouve le chapitre le plus pertinent. pertinent pour l’enquête, suggérant quel chapitre il faut lire pour trouver une réponse à cette question telle qu’écrite par l’auteur. Vous pouvez trouver le code pour faire cela ici. Ce code en particulier est celui qui recherche le chapitre le plus pertinent pour une entrée ou une question donnée :

embedded_question = embeddings_model.embed_query("What are the flaws of philosophers?")
similarities = [] 
tags = []
for i2 in range(len(emb_list)):
    similarities.append(cosine_similarity(emb_list[i2], embedded_question))
    tags.append(f"CHAPTER {i2}")

print(tags[similarities.index(max(similarities))])

Les similitudes d’intégration entre chaque chapitre et l’entrée sont regroupées dans une liste (similarities) et le numéro de chaque chapitre est mis dans le tags liste. Le chapitre le plus pertinent est ensuite imprimé en utilisant print(tags[similarities.index(max(similarities))])qui obtient le numéro de chapitre du tags liste qui correspond à la valeur maximale de la similarities liste.

Sortir:

CHAPTER 1

Voici comment ce code fonctionne visuellement.

Organigramme du fonctionnement du code d'intégration

Autres idées d’applications

Il existe de nombreuses autres utilisations analytiques des textes volumineux avec LangChain et LLM, et même si elles sont trop complexes pour être couvertes dans leur intégralité dans cet article, je vais en énumérer quelques-unes et expliquer comment elles peuvent être réalisées dans cette section.

Visualiser les sujets

Vous pouvez, par exemple, prendre des transcriptions de vidéos YouTube liées à l’IA, comme celles de cet ensemble de donnéesextrayez les outils liés à l’IA mentionnés dans chaque vidéo (LangChain, OpenAI, TensorFlow, etc.), compilez-les dans une liste et recherchez les outils d’IA les plus mentionnés dans l’ensemble, ou utilisez un graphique à barres pour visualiser la popularité de chacun.

Analyser les transcriptions des podcasts

Vous pouvez prendre des transcriptions de podcasts et, par exemple, trouver des similitudes et des différences entre les différents invités en termes d’opinions et de sentiments sur un sujet donné. Vous pouvez également créer un script d’intégration (comme celui de cet article) qui recherche dans les transcriptions du podcast les conversations les plus pertinentes en fonction d’une entrée ou d’une question.

Analyser les évolutions des articles d’actualité

Il existe de nombreux grands ensembles de données d’articles d’actualité, comme celui-ci sur les titres et descriptions de l’actualité de la BBC et celui-ci sur les titres et descriptions de l’actualité financière. À l’aide de ces ensembles de données, vous pouvez analyser des éléments tels que les sentiments, les sujets et les mots-clés pour chaque article d’actualité. Vous pouvez alors visualiser comment ces aspects des articles d’actualité évoluent au fil du temps.

Conclusion

J’espère que vous avez trouvé cela utile et que vous avez maintenant une idée de la façon d’analyser de grands ensembles de données textuelles avec LangChain en Python en utilisant différentes méthodes telles que les intégrations et l’extraction de données. Bonne chance dans vos projets LangChain !




Source link

décembre 19, 2023