MATH60230 : Séance 10

Analyse de texte et traitement du langage naturel

Vincent Grégoire

HEC Montréal

Saad Ali Khan

HEC Montréal

Plan pour aujourd’hui

  • Introduction à l’analyse de texte en finance
  • Fondamentaux du prétraitement de texte
  • Représentation du texte : BoW, TF-IDF, dictionnaires
  • Plongements de mots et de documents
  • Transformers et grands modèles de langage (LLM)
  • Considérations pratiques pour la recherche

Qu’est-ce que l’analyse de texte ?

  • L’analyse de texte (fouille de texte, TAL) est le processus d’extraction d’informations structurées à partir de texte non structuré
  • Transformer des mots en nombres utilisables pour :
    • L’analyse statistique
    • L’apprentissage automatique
    • La recherche d’information
  • Le traitement automatique du langage naturel (TAL ou NLP) fournit les outils et techniques

Pourquoi l’analyse de texte en finance ?

  • D’immenses quantités d’information précieuse existent sous forme de texte :
    • Dépôts réglementaires (10-K, 10-Q, 8-K aux États-Unis)
    • Transcriptions de conférences téléphoniques sur les résultats
    • Articles de presse et communiqués
    • Rapports d’analystes
    • Médias sociaux (Twitter/X, Reddit, StockTwits)
    • Communications des banques centrales
  • Les bases de données structurées traditionnelles (CRSP, Compustat) sont bien étudiées
  • Les données textuelles offrent de nouvelles sources de données pour répondre à de nouvelles questions de recherche

Applications du TAL en finance

Application Description Exemple
Analyse de sentiment Mesurer le ton/l’humeur du texte Cette conférence est-elle positive ou négative ?
Extraction d’information Extraire des faits spécifiques Quel est le chiffre d’affaires déclaré ?
Reconnaissance d’entités Identifier des entités Quelles entreprises sont mentionnées ?
Classification de documents Catégoriser les documents Quels sujets ce 10-K aborde-t-il ?
Détection d’événements Identifier des événements Cette nouvelle concerne-t-elle une F&A ?
Résumé Condenser le texte Résumer ce dépôt de 100 pages

Analyse de sentiment en finance

  • Quantifier le ton des communications financières
  • Applications :
    • Prédire les rendements boursiers à partir du sentiment des nouvelles
    • Mesurer la confiance de la direction dans les conférences
    • Détecter les changements de ton dans les communications de la Fed
    • Agréger le sentiment des médias sociaux
  • Constat clé : le sentiment dans les textes financiers diffère du sentiment général
    • « Liability » (passif) est négatif en anglais courant, neutre en finance

Reconnaissance d’entités nommées (NER)

  • Identifier et classifier les entités nommées dans le texte :
    • Organisations : Apple Inc., Réserve fédérale
    • Personnes : Warren Buffett, Jerome Powell
    • Lieux : New York, Silicon Valley
    • Termes financiers : chiffre d’affaires, BAIIA, capitalisation boursière
    • Dates et montants : T3 2024, 5,2 milliards $
  • Des modèles NER spécifiques à la finance existent (p. ex., FinBERT-NER)
  • Cas d’usage : construire des graphes de connaissances des relations entre entreprises

Le pipeline d’analyse de texte

flowchart LR
    A[Texte brut] --> B[Prétraitement]
    B --> C[Tokenisation]
    C --> D[Normalisation]
    D --> E[Représentation]
    E --> F[Analyse/AA]

    style A fill:#e1f5fe
    style F fill:#c8e6c9

  1. Prétraitement : Nettoyer le texte brut
  2. Tokenisation : Découper en mots/sous-mots
  3. Normalisation : Standardiser les jetons
  4. Représentation : Convertir en caractéristiques numériques
  5. Analyse : Appliquer des méthodes statistiques/AA

Tokenisation

Tokenisation = découper le texte en unités individuelles (jetons)

text = "Apple's Q3 revenue was $81.8 billion."

# Tokenisation simple par espaces
tokens = text.split()
# ['Apple's', 'Q3', 'revenue', 'was', '$81.8', 'billion.']

# Mieux : utiliser un tokeniseur
from nltk.tokenize import word_tokenize
tokens = word_tokenize(text)
# ['Apple', "'s", 'Q3', 'revenue', 'was', '$', '81.8', 'billion', '.']
  • Défis : contractions, mots composés, nombres, ponctuation

Mots vides (stop words)

Mots vides = mots courants qui portent peu de sens

  • Exemples : « le », « est », « à », « qui », « sur », « un », « une »
from nltk.corpus import stopwords

stop_words = set(stopwords.words('french'))
tokens = ['la', 'entreprise', 'a', 'déclaré', 'une', 'forte', 'croissance']
filtered = [w for w in tokens if w.lower() not in stop_words]
# ['entreprise', 'déclaré', 'forte', 'croissance']
  • Supprimer les mots vides réduit le bruit et la dimensionnalité
  • Mais : parfois les mots de contexte comptent (p. ex., « pas rentable »)

Racinisation et lemmatisation

Réduire les mots à leur forme racine pour regrouper les mots apparentés :

Racinisation (stemming)

  • Troncature grossière basée sur des règles
  • Rapide mais imprécise
  • « courant » → « cour »
  • « études » → « étud »
from nltk.stem import PorterStemmer
stemmer = PorterStemmer()
stemmer.stem("profitable")
# 'profit'

Lemmatisation

  • Utilise le vocabulaire et la morphologie
  • Plus lente mais précise
  • « courant » → « courir »
  • « études » → « étude »
from nltk.stem import WordNetLemmatizer
lemmatizer = WordNetLemmatizer()
lemmatizer.lemmatize("profitable", pos='a')
# 'profitable'

N-grammes

N-grammes = séquences contiguës de n jetons

  • Unigrammes (n=1) : mots individuels
  • Bigrammes (n=2) : paires de mots consécutifs
  • Trigrammes (n=3) : triplets de mots consécutifs
from nltk import ngrams

text = ["taux", "intérêt", "hausse", "attendue"]
list(ngrams(text, 2))
# [('taux', 'intérêt'), ('intérêt', 'hausse'), ('hausse', 'attendue')]
  • Capture les expressions : « taux d’intérêt » vs. « taux » + « intérêt »
  • Compromis : plus de contexte vs. données éparses

Sac de mots (Bag of Words)

La représentation de texte la plus simple : compter les occurrences de mots

from sklearn.feature_extraction.text import CountVectorizer

docs = [
    "revenue increased significantly",
    "profit margins decreased",
    "revenue and profit both increased"
]

vectorizer = CountVectorizer()
X = vectorizer.fit_transform(docs)
print(vectorizer.get_feature_names_out())
# ['and', 'both', 'decreased', 'increased', 'margins',
#  'profit', 'revenue', 'significantly']
  • Résultat : matrice document-terme (documents × mots)
  • Ignore l’ordre des mots (« sac » de mots)

TF-IDF

Fréquence du terme - Fréquence inverse de document

  • TF (Term Frequency) : fréquence d’un mot dans un document
  • IDF (Inverse Document Frequency) : rareté d’un mot dans tous les documents

\text{TF-IDF}(t, d) = \text{TF}(t, d) \times \log\left(\frac{N}{\text{DF}(t)}\right)

  • Les mots fréquents dans un document mais rares globalement obtiennent des scores élevés
  • Les mots communs à tous les documents obtiennent des scores faibles
  • Meilleur que les comptages bruts pour identifier les termes distinctifs

TF-IDF en Python

from sklearn.feature_extraction.text import TfidfVectorizer

docs = [
    "The company reported strong revenue growth in Q3",
    "Revenue declined due to market conditions",
    "Strong earnings beat analyst expectations"
]

vectorizer = TfidfVectorizer(stop_words='english')
X = vectorizer.fit_transform(docs)

# X est maintenant une matrice creuse de caractéristiques TF-IDF
print(X.shape)  # (3 documents, n caractéristiques)
  • TfidfVectorizer combine tokenisation, suppression des mots vides et TF-IDF
  • On peut spécifier ngram_range=(1, 2) pour inclure les bigrammes

Méthodes basées sur les dictionnaires

Utiliser des listes de mots prédéfinies pour mesurer des concepts spécifiques :

  1. Créer/obtenir un dictionnaire de mots pour chaque catégorie
  2. Compter les occurrences des mots du dictionnaire dans le texte
  3. Calculer des scores (p. ex., % de mots positifs, sentiment net)
  • Simple, interprétable et transparent
  • Aucun entraînement requis
  • Mais : indépendant du contexte (même mot = même sens)

Dictionnaire Loughran-McDonald

Le dictionnaire de sentiment standard pour les textes financiers (Loughran and McDonald 2011)

  • Développé spécifiquement pour les dépôts 10-K
  • Catégories : Négatif, Positif, Incertitude, Litigieux, Contraignant, Modal fort, Modal faible
Catégorie Exemples de mots
Négatif loss, decline, adverse, deficit, litigation
Positif achieve, benefit, gain, improve, profitable
Incertitude approximate, contingent, possible, risk
Litigieux attorney, court, lawsuit, legal, tribunal

Disponible sur : sraf.nd.edu/loughranmcdonald-master-dictionary

Utilisation de Loughran-McDonald

import pandas as pd

# Charger le dictionnaire
lm_dict = pd.read_csv('LoughranMcDonald_MasterDictionary.csv')

# Obtenir les mots négatifs
negative_words = set(
    lm_dict[lm_dict['Negative'] > 0]['Word'].str.lower()
)

# Compter les mots négatifs dans le texte
def count_negative(text):
    words = text.lower().split()
    return sum(1 for w in words if w in negative_words)

# Calculer un score de sentiment
def sentiment_score(text):
    words = text.lower().split()
    n_neg = sum(1 for w in words if w in negative_words)
    n_pos = sum(1 for w in words if w in positive_words)
    return (n_pos - n_neg) / len(words)

Limites du BoW/TF-IDF

  • Pas de sens sémantique : « bon » et « excellent » sont des vecteurs non reliés
  • Haute dimensionnalité : le vocabulaire peut dépasser 10 000 mots
  • Représentations creuses : la plupart des entrées sont nulles
  • Pas de contexte : « banque » (financière) vs. « banque » (de rivière) sont identiques
  • Ordre des mots perdu : « le chien mord l’homme » = « l’homme mord le chien »

Solution : plongements de mots — représentations denses et sémantiques

Plongements de mots (Word Embeddings)

Associer les mots à des vecteurs denses où les mots similaires sont proches

%%{init: {'theme': 'base', 'themeVariables': {'clusterBkg': '#f5f5f5', 'clusterBorder': '#cccccc'}}}%%
flowchart LR
    subgraph "Creux (BoW)"
        A["roi: [0,0,1,0,0,...]<br/>reine: [0,1,0,0,0,...]<br/>homme: [1,0,0,0,0,...]"]
    end
    subgraph "Dense (Plongement)"
        B["roi: [0.2, 0.8, -0.1, ...]<br/>reine: [0.3, 0.7, -0.2, ...]<br/>homme: [0.1, 0.6, 0.4, ...]"]
    end
    A --> B

    style A fill:#ffcdd2
    style B fill:#c8e6c9

  • Typiquement 100-300 dimensions (vs. 10 000+ pour BoW)
  • Appris à partir de grands corpus de texte
  • Capturent les relations sémantiques

Word2Vec

La méthode fondatrice des plongements de mots (Mikolov et al. 2013)

Idée clé : « On connaît un mot par la compagnie qu’il garde »

  • Entraîner un réseau de neurones pour prédire :
    • CBOW : prédire le mot à partir du contexte
    • Skip-gram : prédire le contexte à partir du mot
  • Exemple célèbre : \text{roi} - \text{homme} + \text{femme} \approx \text{reine}
  • Modèles pré-entraînés disponibles (Google News, GloVe, FastText)

Utilisation de plongements pré-entraînés

import gensim.downloader as api

# Charger des plongements Word2Vec pré-entraînés
model = api.load('word2vec-google-news-300')

# Trouver des mots similaires
model.most_similar('profit')
# [('profits', 0.82), ('earnings', 0.71), ('revenue', 0.65), ...]

# Arithmétique de mots
model.most_similar(positive=['ceo', 'woman'], negative=['man'])
# [('chairwoman', 0.71), ('executive', 0.69), ...]

# Obtenir le vecteur de plongement
vector = model['stock']  # vecteur de 300 dimensions
  • GloVe, FastText sont des alternatives avec une utilisation similaire

Plongements de documents

Comment représenter un document entier comme un vecteur ?

Approche simple : moyenner les plongements de mots

import numpy as np

def document_embedding(text, model):
    words = text.lower().split()
    vectors = [model[w] for w in words if w in model]
    if vectors:
        return np.mean(vectors, axis=0)
    return np.zeros(model.vector_size)
  • Fonctionne raisonnablement bien pour les textes courts
  • Perd l’ordre des mots et la pondération par importance
  • Meilleures méthodes : Doc2Vec, Sentence-BERT, plongements LLM

Le problème du contexte

Les plongements traditionnels donnent un vecteur par mot :

« La banque a relevé les taux d’intérêt » « Je me suis assis au bord de la banque de sable »

Même vecteur pour « banque » dans les deux phrases !

Solution : plongements contextuels des Transformers

  • Vecteur différent pour le même mot selon le contexte
  • A révolutionné le TAL à partir de BERT (2018)

L’architecture Transformer

La fondation de l’architecture pour le TAL moderne (Vaswani et al. 2017)

  • Auto-attention : chaque mot prête attention à tous les autres
  • Capture les dépendances à longue distance
  • Parallélisable (contrairement aux RNN)

Mécanisme d’attention (intuition)

Pour chaque mot, calculer des poids d’attention vers tous les autres mots :

« L’entreprise a déclaré que son chiffre d’affaires a augmenté »

  • « son » prête fortement attention à « entreprise » (apprend la référence)
  • La représentation de chaque mot est une somme pondérée de tous les mots
  • Permet au modèle de comprendre :
    • La coréférence (« son » réfère à « entreprise »)
    • Les dépendances à longue distance
    • La désambiguïsation du sens des mots

BERT : encodeur bidirectionnel

Bidirectional Encoder Representations from Transformers (Devlin et al. 2019)

  • Pré-entraîné sur un corpus de texte massif (Wikipédia + livres)
  • Deux objectifs de pré-entraînement :
    • Modèle de langue masqué : prédire les mots masqués
    • Prédiction de phrase suivante : deux phrases sont-elles consécutives ?
  • Affiner sur des tâches en aval :
    • Classification de sentiment
    • Reconnaissance d’entités nommées
    • Réponse aux questions

Transformers spécifiques à la finance

Le BERT général peut ne pas bien comprendre le langage financier

Variantes de FinBERT (Araci 2019) :

from transformers import pipeline

classifier = pipeline("sentiment-analysis",
                      model="ProsusAI/finbert")

classifier("Revenue growth exceeded expectations")
# [{'label': 'positive', 'score': 0.94}]

Utilisation des Transformers pour les plongements

from sentence_transformers import SentenceTransformer

model = SentenceTransformer('all-MiniLM-L6-v2')

sentences = [
    "The company reported strong earnings",
    "Profits exceeded analyst expectations",
    "The weather was sunny today"
]

embeddings = model.encode(sentences)
# embeddings.shape: (3, 384)

# Calculer la similarité
from sklearn.metrics.pairwise import cosine_similarity
similarity = cosine_similarity(embeddings)
# les phrases 0 et 1 auront une forte similarité
  • Utiliser pour la recherche sémantique, le clustering, la classification

Grands modèles de langage (LLM)

LLM = très grands modèles Transformer entraînés sur de vastes corpus

  • GPT-4, Claude, Llama, Gemini, Mistral…
  • Milliards de paramètres
  • Entraînés sur des données à l’échelle d’Internet

Capacité clé : peut effectuer des tâches à partir d’instructions (prompts)

  • Pas d’entraînement spécifique requis
  • Apprentissage « zero-shot » et « few-shot »
  • Peut suivre des instructions complexes

Capacités des LLM pour la finance

Tâche Exemple de prompt
Sentiment « Cette conférence est-elle positive, négative ou neutre ? »
Classification « Quels facteurs de risque sont discutés dans cette section du 10-K ? »
Extraction « Extraire le chiffre d’affaires et le bénéfice net de ce texte »
Résumé « Résumer ce 10-K en 3 points »
Q&R « D’après ce dépôt, quels sont les principaux risques d’affaires ? »
NER « Lister toutes les entreprises mentionnées dans cet article »
  • Pas d’entraînement requis — il suffit d’écrire de bons prompts
  • Peut gérer les nuances et le contexte mieux que les méthodes à base de règles

Utilisation de l’API OpenAI

from openai import OpenAI

client = OpenAI()  # Utilise la variable d'environnement OPENAI_API_KEY

response = client.chat.completions.create(
    model="gpt-5-mini",
    messages=[
        {"role": "system", "content": "You are a financial analyst."},
        {"role": "user", "content": """
            Classify the sentiment of this text as
            positive, negative, or neutral:

            "Despite challenging market conditions,
            the company achieved record revenue growth."
        """}
    ]
)

print(response.choices[0].message.content)
# "positive"

Ingénierie de prompts

L’art d’écrire des prompts efficaces :

  1. Être spécifique : définir clairement la tâche et le format de sortie attendu
  2. Fournir du contexte : expliquer le domaine (finance, comptabilité, etc.)
  3. Donner des exemples : l’apprentissage few-shot améliore la précision
  4. Définir des contraintes : « répondre uniquement par : positif, négatif, neutre »
prompt = """
You are a financial sentiment analyst. Classify the following
text as exactly one of: POSITIVE, NEGATIVE, NEUTRAL.

Example: "Revenue increased 15%" -> POSITIVE
Example: "We face significant headwinds" -> NEGATIVE

Text: "{text}"
Classification:
"""

LLM locaux

Exécuter des LLM localement pour la confidentialité et le contrôle des coûts :

import ollama

response = ollama.chat(
    model='llama3.2',
    messages=[{
        'role': 'user',
        'content': 'Summarize this earnings report in one sentence: ...'
    }]
)

print(response['message']['content'])
  • Ollama : outil en ligne de commande pour le déploiement local de LLM
  • LM Studio : application GUI pour exécuter des LLM locaux
  • Modèles : Llama 3, Mistral, Phi, Gemma, Qwen, etc.
  • Compromis : modèles plus petits = moins capables mais gratuits et privés

Défi de recherche : biais d’anticipation

Biais d’anticipation (look-ahead bias) = utiliser des informations non disponibles au moment de l’analyse

Dans la recherche en TAL, cela peut survenir par :

  1. Données d’entraînement du modèle : GPT-4 a été entraîné sur des données jusqu’à une date limite
    • L’utiliser pour « prédire » des événements avant cette date est de la triche
  1. Dates de publication des modèles : On ne peut pas utiliser GPT-4 pour des prédictions de 2020
    • Documenter quelle version du modèle vous avez utilisée
  1. Disponibilité du texte : Quand le document était-il réellement public ?
    • Date de dépôt du 10-K vs. fin de l’exercice fiscal

Défi de recherche : reproductibilité

La recherche basée sur les LLM fait face à des défis uniques de reproductibilité :

  • Versionnage des modèles : les API sont mises à jour silencieusement
    • Documenter le nom exact du modèle : gpt-4-0613 et non pas juste gpt-4
  • Dépréciation des API : les modèles sont retirés
    • Considérer les modèles locaux pour la reproductibilité à long terme
  • Sorties stochastiques : même prompt → réponses différentes
    • Mettre temperature=0 pour des sorties déterministes
    • Sauvegarder toutes les sorties brutes

Température et échantillonnage

La température contrôle l’aléatoire des sorties des LLM :

  • temperature=0 : déterministe, toujours choisir le jeton le plus probable
  • temperature=1 : échantillonner selon les probabilités du modèle
  • temperature>1 : plus aléatoire/créatif
response = client.chat.completions.create(
    model="gpt-5-mini",
    temperature=0,  # Sorties reproductibles
    messages=[...]
)

Pour la recherche : utiliser temperature=0 pour la reproductibilité, mais noter que la plupart des modèles performent mieux à des températures plus élevées (typiquement 0,7-1,0)

Sortie structurée

Les LLM produisent du texte, mais on a souvent besoin de données structurées :

response = client.chat.completions.create(
    model="gpt-5-mini",
    response_format={"type": "json_object"},
    messages=[{
        "role": "user",
        "content": """Extract financial data as JSON:
        {"revenue": number, "net_income": number, "sentiment": string}

        Text: Revenue was $5.2B, net income $800M.
        Management expressed cautious optimism."""
    }]
)
# {"revenue": 5200000000, "net_income": 800000000,
#  "sentiment": "cautiously positive"}
  • Utiliser le mode JSON pour un parsing fiable
  • Définir des schémas clairs dans les prompts

Sortie structurée avec Pydantic

from pydantic import BaseModel
from openai import OpenAI

class FinancialExtraction(BaseModel):
    revenue: float | None
    net_income: float | None
    sentiment: str
    confidence: float

client = OpenAI()
completion = client.beta.chat.completions.parse(
    model="gpt-5-mini",
    messages=[
        {"role": "system", "content": "Extract financial information."},
        {"role": "user", "content": "Revenue grew 15% to $5.2B..."}
    ],
    response_format=FinancialExtraction,
)

result = completion.choices[0].message.parsed
print(result.revenue)  # 5200000000.0

Flux de travail LLM pour la recherche

flowchart LR
    A[Documents] --> B[Template de prompt]
    B --> C[API LLM]
    C --> D[Parser la réponse]
    D --> E[Valider]
    E --> F[Stocker les résultats]
    F --> G[Analyse]

    E -->|Invalide| B

    style A fill:#e1f5fe
    style G fill:#c8e6c9

  • Traitement par lots : traiter les documents en parallèle
  • Gestion des erreurs : échecs d’API, limites de débit, réponses invalides
  • Validation : vérifier que les sorties correspondent au format attendu
  • Journalisation : sauvegarder les prompts, réponses et métadonnées

Considérations de coûts

Les API de LLM facturent par jeton (≈ 0,75 mots) :

Modèle Entrée Sortie
GPT-5.2 (OpenAI) 1,75 $/1M jetons 14 $/1M jetons
GPT-5 mini (OpenAI) 0,25 $/1M jetons 2 $/1M jetons
Claude Sonnet 4.5 (Anthropic) 3 $/1M jetons 15 $/1M jetons
Claude Haiku 4.5 (Anthropic) 1 $/1M jetons 5 $/1M jetons
  • 10 000 documents × 1 000 jetons chacun = 10M jetons
  • Avec GPT-5 mini : ~22,50 $ pour le traitement
  • Commencer avec des modèles plus petits/moins chers pour le développement
  • Considérer les modèles locaux pour le traitement à grande échelle

Résumé des bibliothèques Python

Bibliothèque Cas d’usage
NLTK TAL classique : tokenisation, racinisation, corpus
spaCy TAL industriel : pipelines rapides et prêts pour la production
scikit-learn BoW, TF-IDF, classification de texte
Gensim Word2Vec, Doc2Vec, modélisation de sujets
Transformers BERT, FinBERT, modèles de pointe
Sentence-Transformers Plongements de documents, recherche sémantique
OpenAI Modèles GPT via API
Ollama Déploiement local de LLM

Résumé des meilleures pratiques

  1. Commencer simple : les dictionnaires et TF-IDF sont des bases interprétables
  1. Utiliser des ressources spécifiques au domaine : Loughran-McDonald, FinBERT
  1. Tout documenter : versions des modèles, prompts, paramètres
  1. Mettre temperature=0 : pour une recherche reproductible
  1. Valider les sorties : les LLM peuvent halluciner ou mal formater
  1. Considérer les coûts : traitement par lots, sélection de modèle
  1. Éviter le biais d’anticipation : respecter les dates limites d’entraînement des modèles

Références

Lectures essentielles :

Livres (disponibles via la bibliothèque HEC) :

Vidéos :

Références

Araci, Dogu. 2019. “FinBERT: Financial Sentiment Analysis with Pre-Trained Language Models.” arXiv Preprint arXiv:1908.10063.
Devlin, Jacob, Ming-Wei Chang, Kenton Lee, and Kristina Toutanova. 2019. “BERT: Pre-Training of Deep Bidirectional Transformers for Language Understanding.” Proceedings of the 2019 Conference of the North American Chapter of the Association for Computational Linguistics: Human Language Technologies, 4171–86.
Gentzkow, Matthew, Bryan Kelly, and Matt Taddy. 2019. “Text as Data.” Journal of Economic Literature 57 (3): 535–74.
Jurafsky, Dan, and James H. Martin. 2025. Speech and Language Processing: An Introduction to Natural Language Processing, Computational Linguistics, and Speech Recognition with Language Models. 3rd ed. https://web.stanford.edu/~jurafsky/slp3/.
Loughran, Tim, and Bill McDonald. 2011. “When Is a Liability Not a Liability? Textual Analysis, Dictionaries, and 10-Ks.” The Journal of Finance 66 (1): 35–65.
Mikolov, Tomas, Kai Chen, Greg Corrado, and Jeffrey Dean. 2013. “Efficient Estimation of Word Representations in Vector Space.” arXiv Preprint arXiv:1301.3781.
Vaswani, Ashish, Noam Shazeer, Niki Parmar, Jakob Uszkoreit, Llion Jones, Aidan N Gomez, Łukasz Kaiser, and Illia Polosukhin. 2017. “Attention Is All You Need.” Advances in Neural Information Processing Systems 30.