[PYTHON] J'ai essayé de construire un modèle d'estimation des titres d'articles susceptibles de faire le buzz avec Qiita

J'ai touché à Python, mais j'ai peu d'expérience dans la mise en œuvre de l'apprentissage automatique. → Je veux surtout faire quelque chose en utilisant le traitement du langage naturel Avec ce sentiment, j'ai construit un modèle d'estimation de buzz.

Aperçu

la mise en oeuvre

Collecter des données de titre d'article

Articles sur la tendance

Obtenez-le à partir du compte Twitter (Qiita Popular Posts) qui présente les articles tendance à l'aide de l'API Twitter. 3229 données seront collectées, l'URL et les pictogrammes du tweet seront supprimés, puis sauvegardés dans le fichier json.

def retrieveTweets(screenName, count):
    global totalIdx
    timeLine = t.statuses.user_timeline(screen_name=screenName, count=count)
    maxId = 0
    for tweetsIdx, tweet in enumerate(timeLine):
        maxId = tweet["id"]
        addArticleTitles(tweet)
        totalIdx += 1
    print("Starting additional retrieving...")
    retrieveContinuedTweets(screenName, count, maxId)

def retrieveContinuedTweets(screenName, count, maxId):
    global totalIdx, isFinished
    tmpMaxId = maxId
    while True:
        timeLine = t.statuses.user_timeline(screen_name=screenName, count=count, max_id=tmpMaxId)
        prevMaxId = 0
        for tweetsIdx, tweet in enumerate(timeLine):
            tmpMaxId = tweet["id"]
            addArticleTitles(tweet)
            print("totalIdx = {}, prevMaxId = {}, maxId = {}, title = {}\n".format(totalIdx, prevMaxId, tmpMaxId, trendArticleTitles[totalIdx]["articleTitle"]))
            if prevMaxId == 0 and totalIdx % 200 != 0:
                isFinished = True
                break
            prevMaxId = tmpMaxId
            totalIdx += 1
        if isFinished:
            print("Finished collecting {} qiita_trend_titles.".format(totalIdx))
            break

def addArticleTitles(tweet):
    global trendArticleTitles
    tmpTitle = re.sub(r"(https?|ftp)(:\/\/[-_\.!~*\'()a-zA-Z0-9;\/?:\@&=\+\$,%#]+)", "", tweet["text"]) #Supprimer l'URL dans les tweets
    tmpTitle = ''.join(s for s in tmpTitle if s not in emoji.UNICODE_EMOJI)
    articleTitle = tmpTitle[:len(tmpTitle)-1] #Retirez l'espace demi-largeur à la fin
    datum = {"articleTitle": articleTitle}
    trendArticleTitles.append(datum)

Article régulier

Utilisez l'API Qiita pour obtenir les titres des articles réguliers qui ne sont pas en vogue. Ici, 9450 données ont été collectées et sauvegardées dans un fichier json ainsi que des titres d'articles de tendance.

articleTitles = []
idx = 0
print("Starting collecting article titles...")
for page in range(3, 101):
    #Exclure les premières pages pour exclure les articles des comptes de spam
    params = {"page": str(page), "per_page": str(per_page)}
    response = requests.get(url, headers=headers, params=params)
    resJson = response.json()
    for article in resJson:
        if article.get("likes_count") < notBuzzThreshold:
            title = article.get("title")
            articleTitles.append({"articleTitle": title})
            print("{}th article title = {}, url = {}".format(idx, title, article["url"]))
            idx += 1
print("Finished collecting {} qiita_article_titles.".format(idx))

Combinez les ensembles de données de titre d'article dans un seul fichier

Commencez par charger les deux types de données de titre d'article collectées ci-dessus. Tout en ajoutant un indicateur indiquant s'il s'agit d'un article de tendance, nous le terminerons comme une seule donnée. Au cas où, mélangez le contenu des données combinées.

Encore une fois, le fichier json est vidé à la fin et la collecte de données est terminée.

mergedData = []
for datum in trendData:
    mergedData.append({
        "articleTitle": datum["articleTitle"],
        "isTrend": 1
    })
for datum in normalData:
    mergedData.append({
        "articleTitle": datum["articleTitle"],
        "isTrend": 0
    })

#Mélangez l'ordre des résultats combinés
random.shuffle(mergedData)
print("Finished shuffling 'Merged Article Titles'.")

Pratiquez la détection de spam

J'ai essayé de construire un modèle d'estimation à l'aide de Naive Bayes, mais je ne savais pas par quoi commencer. Par conséquent, j'ai examiné Naive Bayes lui-même et essayé un article qui implémente la détection de spam dans Naive Bayes afin que je puisse en avoir une idée avant cette implémentation.

Étude Naive Bays

Naive Bayes-Practice avec détection de spam

Maintenant que j'ai beaucoup appris sur Naive Bayes, je suis passé à la mise en œuvre pratique. J'ai continué le long de la ↓. Apprentissage automatique ~ Classification du courrier indésirable (classificateur Naive Bayes) ~

Remplacé par l'ensemble de données de l'article Qiita

Maintenant que vous avez une idée de Naive Bayes, il est temps d'entrer dans le sujet principal. J'écrirai sur les parties qui ont été modifiées à partir de la mise en œuvre de l'article utilisé dans la pratique.

Installez MeCab, ipadic-NEologd

Puisque l'ensemble de données de détection de spam est en anglais, il peut être jeté directement dans scicit-learn, mais le titre de l'article Qiita ne le fait pas. Tout d'abord, ajoutez MeCab et ipadic-NEologd afin que vous puissiez bien diviser les mots en japonais. (Le résultat de la division a été obtenu avec CountVectorizer, mais ce n'était pas naturel.)

Je me suis principalement référé au site ci-dessous.

Construction de modèles

À partir de la mise en œuvre de la pratique de détection de spam, nous avons ajouté ce qui suit:

def getStopWords():
    stopWords = []
    with open("./datasets/Japanese.txt", mode="r", encoding="utf-8") as f:
        for word in f:
            if word != "\n":
                stopWords.append(word.rstrip("\n"))
    print("amount of stopWords = {}".format(len(stopWords)))
    return stopWords

def removeEmoji(text):
    return "".join(ch for ch in text if ch not in emoji.UNICODE_EMOJI)

stopWords = getStopWords()
tagger = MeCab.Tagger("mecabrc")
def extractWords(text):
    text = removeEmoji(text)
    text = neologdn.normalize(text)
    words = []
    analyzedResults = tagger.parse(text).split("\n")
    for result in analyzedResults:
        splittedWord = result.split(",")[0].split("\t")[0]
        if not splittedWord in stopWords:
            words.append(splittedWord)
    return words

Si vous passez la méthode de fractionnement de mots à l'analyseur d'arguments de CountVectorizer, il semble que le japonais se divise également bien. génial.

vecCount = CountVectorizer(analyzer=extractWords, min_df=3)

Résultat d'exécution

Nous avons préparé trois textes pour la prédiction: "" "J'ai sorti l'application" , "Unity tutorial" , "Git command memo" `. "J'ai essayé de publier l'application" est censé être "bourdonnant".

Count Vectorizer sans analyseur spécifié

De toute évidence, le nombre de mots est faible. Je pense qu'il n'a pas été divisé normalement.

word size:  1016
word content:  {'De': 809, 'ms': 447, 'nginx': 464, 'django': 232, 'intellij': 363}
Train accuracy = 0.771
Test accuracy = 0.747
[0 0 0]

Désigner le NEoglod de MeCab comme analyseur morphologique

Il semble que les mots peuvent être divisés, mais il y a beaucoup de mots ... Le classement est comme prévu.

word size:  3870
word content:  {'De': 1696, 'MS': 623, 'Teams': 931, 'À': 1853, 'notification': 3711}
Train accuracy = 0.842
Test accuracy = 0.783
[1 0 0]

Supprimer les mots vides et les pictogrammes

Le nombre de mots a été réduit et la précision des données de test a légèrement augmenté. J'ai ressenti l'importance du prétraitement.

word size:  3719
word content:  {'MS': 623, 'Teams': 931, 'À': 1824, 'notification': 3571, 'Faire': 1735}
Train accuracy = 0.842
Test accuracy = 0.784
[1 0 0]

Ajout de divers processus de normalisation

La précision des données d'entraînement a légèrement diminué, mais la précision des données de test a augmenté en conséquence. De plus, j'ai oublié d'afficher la probabilité de classification, je vais donc l'afficher ici. Le texte que j'imaginais bourdonnant a été honnêtement surpris avec une probabilité plus élevée que ce à quoi je m'attendais. (Ce n'est pas fiable à moins que vous ne l'essayiez avec plus de textes ...)

word size:  3700
word content:  {'MS': 648, 'Teams': 955, 'À': 1838, 'notification': 3583, 'Faire': 1748}
[1 0 0]
[[0.23452364 0.76547636]
 [0.92761086 0.07238914]
 [0.99557625 0.00442375]]
Train accuracy = 0.841
Test accuracy = 0.785

Considérations / problèmes, etc.

Cette fois, il semblait que le changement de précision était dans la plage de l'erreur. Comme je ne pouvais garantir que les termes minimaux contenus dans NEologd, j'ai pensé que la précision pouvait être améliorée en couvrant la vectorisation des termes techniques. Après cela, il semble que la précision s'améliorera même si vous extrayez des mots importants du titre de l'article et du contenu de l'article avec TF-IDF etc. et que vous les utilisez.

Recommended Posts

J'ai essayé de construire un modèle d'estimation des titres d'articles susceptibles de faire le buzz avec Qiita
J'ai essayé de créer un environnement Ubuntu 20.04 LTS + ROS2 avec Raspberry Pi 4
J'ai essayé de résumer les opérations susceptibles d'être utilisées avec numpy-stl
J'ai essayé de créer un article dans Wiki.js avec SQL Alchemy
J'ai essayé d'obtenir le code d'authentification de l'API Qiita avec Python.
J'ai essayé de prédire le comportement du nouveau virus corona avec le modèle SEIR.
J'ai essayé de détecter un objet avec M2Det!
J'ai essayé de créer un modèle avec l'exemple d'Amazon SageMaker Autopilot
J'ai essayé de créer un environnement avec WSL + Ubuntu + VS Code dans un environnement Windows
J'ai essayé d'extraire des fonctionnalités avec SIFT d'OpenCV
J'ai essayé d'automatiser la mise à jour de l'article du blog Livedoor avec Python et sélénium.
J'ai essayé d'implémenter le perceptron artificiel avec python
J'ai essayé de créer un pipeline ML avec Cloud Composer
J'ai essayé de créer une application OCR avec PySimpleGUI
J'ai essayé de trouver la classe alternative avec tensorflow
J'ai essayé de créer un environnement d'apprentissage automatique avec Python (Mac OS X)
[Python] J'ai essayé de faire une application qui calcule le salaire en fonction des heures de travail avec tkinter
J'ai créé une application avec Lambda qui notifie LINE de "j'aime" à l'aide de l'API Qiita.
J'ai créé une API avec Docker qui renvoie la valeur prédite du modèle d'apprentissage automatique
J'ai essayé de créer un service qui vend des données apprises par machine à une vitesse explosive avec Docker
J'ai essayé de prédire les ventes de logiciels de jeux avec VARISTA en me référant à l'article du Codexa
J'ai essayé de trouver l'entropie de l'image avec python
J'ai essayé de trouver la moyenne de plusieurs colonnes avec TensorFlow
J'ai essayé d'implémenter ListNet d'apprentissage de rang avec Chainer
J'ai essayé d'écrire dans un modèle de langage profondément appris
J'ai essayé d'implémenter SSD avec PyTorch maintenant (édition du modèle)
J'ai essayé de prédire le nombre de personnes infectées au niveau national de la nouvelle corona avec un modèle mathématique
[Python] J'ai essayé d'expliquer des mots difficiles à comprendre pour les débutants d'une manière facile à comprendre.
J'ai essayé de créer un langage original "PPAP Script" qui imagé PPAP (Pen Pineapple Appo Pen) avec Python
J'ai essayé de faire une activité qui définit collectivement les informations de position
J'ai essayé de gratter le classement du calendrier de l'avent Qiita avec Python
J'ai essayé d'automatiser l'arrosage du pot avec Raspberry Pi
J'ai essayé de créer l'image de démarrage SD de LicheePi Nano
[Python] Un mémo que j'ai essayé de démarrer avec asyncio
J'ai essayé de créer une liste de nombres premiers avec python
J'ai essayé de corriger "J'ai essayé la simulation probabiliste du jeu de bingo avec Python"
J'ai essayé de résumer ce qui était sorti avec Qiita avec Word cloud
J'ai essayé de faire 5 modèles de base d'analyse en 3 ans
J'ai essayé d'agrandir la taille du volume logique avec LVM
J'ai essayé de visualiser Boeing de la performance du violon par estimation de pose
J'ai essayé d'améliorer l'efficacité du travail quotidien avec Python
J'ai essayé de collecter automatiquement des images de Kanna Hashimoto avec Python! !!
J'ai essayé de créer une fonction de similitude d'image avec Python + OpenCV
J'ai essayé de créer un mécanisme de contrôle exclusif avec Go
J'ai essayé de créer un environnement capable d'acquérir, de stocker et d'analyser les données de tweet en WSL (bash)
(Python) J'ai créé une application de Trello qui notifie périodiquement le relâchement des tâches sur le point d'expirer.
J'ai essayé de sortir la liste rpm de la destination de connexion SSH sur une feuille Excel avec Python + openpyxl.
J'ai essayé de mettre en œuvre un apprentissage en profondeur qui n'est pas profond avec uniquement NumPy
J'ai essayé de mettre en œuvre une blockchain qui fonctionne réellement avec environ 170 lignes
J'ai créé un capteur d'ouverture / fermeture (lien Twitter) avec TWE-Lite-2525A
J'ai essayé d'extraire automatiquement les mouvements des joueurs Wiire avec un logiciel
J'ai essayé d'analyser la négativité de Nono Morikubo. [Comparer avec Posipa]
J'ai essayé de rationaliser le rôle standard des nouveaux employés avec Python
J'ai essayé de visualiser le texte du roman "Weather Child" avec Word Cloud
J'ai essayé de visualiser le modèle avec la bibliothèque d'apprentissage automatique low-code "PyCaret"
J'ai essayé d'expliquer le dernier modèle d'estimation de posture "Dark Pose" [CVPR2020]
J'ai essayé d'obtenir les informations sur le film de l'API TMDb avec Python
J'ai essayé de visualiser tous les arbres de décision de la forêt aléatoire avec SVG
J'ai essayé de créer un environnement de développement Mac Python avec pythonz + direnv
[Lambda] J'ai essayé d'incorporer un module externe de python via S3
Je souhaite créer une API qui retourne un modèle avec une relation récursive dans Django REST Framework