[PYTHON] Themenmodell von LDA mit Gensim ~ Nachdenken über den Geschmack des Benutzers vom Qiita-Tag ~

Einführung

In diesem Artikel werde ich versuchen, über Benutzereinstellungen in Bezug auf die Qiita-Tags nachzudenken, die unter Verwendung des LDA-Modells im Gensim der Python-Bibliothek verwendet werden.

Der Zweck besteht darin, zu sehen, wie es aussieht, indem Sie das Themenmodell und Gensim mit den Daten verwenden. Wir hoffen, dass dies eine Gelegenheit für Sie ist, das Themenmodell tatsächlich zu verwenden und detailliert zu studieren.

Ich gehe nicht wirklich darauf ein, wie das Innere des LDA-Modells es implementiert. Konzentrieren Sie sich auf "was Sie tun können". Es berührt auch die Datenerfassung (Scraping usw.).

Es gab auch einen Artikel, der ausführlich erklärt wurde. Wenn Sie sich nach dem Lesen dieses Artikels unzufrieden fühlen, sollten Sie ihn lesen.

Darüber hinaus finden Sie hier zwei Bücher, die tatsächlich in Büchern zu Themenmodellen eingeführt wurden und häufig auch dann vorgestellt werden, wenn Sie sie nachschlagen.

Ich selbst studiere zum Zeitpunkt des Schreibens. Wenn Sie also Fehler oder andere Ratschläge haben, würde ich mich freuen, wenn Sie mich in den Kommentaren darüber informieren könnten.

Was ist ein Themenmodell?

Einfach ausgedrückt ist es ein Modell, das Sätze nach Thema (Kategorie) aus dem Inhalt schätzt und klassifiziert. Das Themenmodell kann Sätze klassifizieren, indem die Wahrscheinlichkeit geschätzt wird, mit der Wörter im Satz erscheinen. Wenn ähnliche Wörter erscheinen, werden sie als dasselbe Thema betrachtet.

Um zu erklären, was Sie tun können, gibt es beispielsweise mehrere Sätze, die in eine beliebige Anzahl von Kategorien eingeteilt werden können. Bereiten Sie beispielsweise 500 Nachrichtenartikel vor. Und wenn Sie dieses Modell bitten, es in 10 Kategorien zu unterteilen, werden 500 Artikel anhand der Wörter im Satz beurteilt und in 10 verwandte Gruppen eingeteilt. Hierbei ist zu beachten, dass es nicht immer möglich ist, jede Gruppe als "Sport" -Kategorie oder "Unterhaltungs" -Kategorie zu bezeichnen. Es kann sich um die Kategorien "Baseball" und "Fußball" anstelle der Kategorien "Sport" handeln. Da es ohne Lehrer lernt, hat es keine spezifische Bezeichnung.

Interessant ist, dass das Modell entscheidet, wie Dinge aufgeteilt werden, die Sie nie für möglich gehalten haben. Wenn Sie sich die stark gewichteten Wörter für jedes Thema ansehen, erhalten Sie möglicherweise einige neue Vorschläge. Wenn Sie die Anzahl der zu teilenden Kategorien ändern, ändert sich auch die Wortgruppe und es wird interessant.

Wie mache ich das Themenmodell?

Übrigens, wenn Sie die Vorgehensweise der Inhalte zusammenfassen, die bisher in den Beispielen enthalten waren, können Sie das Thema Sätze nach der folgenden Vorgehensweise klassifizieren.

  1. Bereiten Sie einen Satz vor
  2. Sätze in Wörter teilen (morphologische Analyse)
  3. Wörter anpassen (Stoppwörter entfernen, Stemming)
  4. Vektorisierung (Wortsack)
  5. Konvertieren Sie in das gewünschte Format und fügen Sie es in das LDA-Modell ein

Der folgende Artikel, der etwas Ähnliches tut, ist hilfreich. Erstellen einer Anwendung mithilfe eines Themenmodells

Auch der folgende Artikel macht etwas Ähnliches, aber am Ende lerne ich mit einem Lehrer in Random Forest anstelle von LDA. Ich finde es interessant, den Unterschied beim Vergleich zu sehen. Klassifizieren Sie Nachrichtenartikel nach scikit-learn und gensim

Was ist diesmal zu tun?

Übrigens scheint LDA auf verschiedene Dinge anwendbar zu sein (so kam es). Also würde ich gerne etwas anderes machen. Von hier aus werden wir endlich das tun, was wir im Titel "Denken Sie an Benutzereinstellungen von Qiita-Tags" angegeben haben.

In den bisherigen Beispielen werden die Sätze anhand der Wörter im Satz kategorisiert. Es

Ich würde gerne LDA ausprobieren, als ob es so wäre.

Implementierung

Verfahren

  1. Datenerfassung
  2. Benutzerdaten
  3. Befolgen Sie die mit den Benutzerdaten verknüpften Tag-Daten
  4. Datenformung
  5. Auf das Modell anwenden

Daten bekommen

Holen Sie sich zuerst die Daten des Benutzers. Dieses Mal werden wir die 1000 besten Leute in der Anzahl der Beiträge zuerst bringen. Ich habe die Daten von Qiita User Ranking verwendet. Qiita-Benutzer werden in der Reihenfolge des Beitrags aufgelistet. Erhalten Sie es also so, wie es ist. Da es 20 Benutzer pro Seite gibt, werden 50 Seiten gecrawlt.

import requests
from bs4 import BeautifulSoup
import csv
import time

base_url = 'https://qiita-user-ranking.herokuapp.com/'
max_page = 50 #20 Benutzer pro Seite

qiita_users = []


for i in range(max_page):
    target_url = base_url + "?page=" + str(i + 1)
    target_html = requests.get(target_url).text
    soup = BeautifulSoup(target_html, 'html.parser')
    users = soup.select('main > p > a') #Speicherort des Benutzernamens

    for k, user in enumerate(users):
        qiita_users.append([(i*20 + k + 1), user.get_text()]) #Benutzer-ID (Rang) und Benutzername

    time.sleep(1) #Intervall von 1 Sekunde, um den Server nicht zu überlasten
    print('scraping page: ' + str(i + 1))

#Daten an CSV spucken
f = open('qiita_users.csv', 'w') 
writer = csv.writer(f, lineterminator='\n')
writer.writerow(['user_id', 'name'])
for user in qiita_users:
    print(user)
    writer.writerow(user)

f.close()

Sie erhalten die folgende CSV.

user_id,name
1,hirokidaichi
2,jnchito
3,suin
4,icoxfog417
5,shu223
...

Als nächstes erhalten Sie die Tag-Daten. Verwenden Sie die von Qiita bereitgestellte API, um die Tag-Daten abzurufen, denen jeder Benutzer folgt. Sie können Tag-Daten in Form von "https://qiita.com/api/v1/users/ (Benutzername) / follow_tags" abrufen. Da die Qiita-API jedoch nur 150 Anfragen pro Stunde akzeptiert, war es nicht möglich, die Daten von 1.000 Tags gleichzeitig zu erfassen. Wenn Sie es dieses Mal nach 1 Stunde erneut ausführen, wird die CSV aktualisiert (7 Mal werden 1.000 Personen erreicht). Selbst wenn die Daten vorerst für 150 Personen erfasst werden, werden sie danach problemlos fortgesetzt. (Die Zahl 1.000 ist in erster Linie angemessen. Wenn Sie sie ändern, erhalten Sie möglicherweise interessante Ergebnisse. Wenn Sie möchten, möchte ich Qiita-Daten direkt mit SQL anstatt über die API abrufen.)

import csv, requests, os.path, time

#Verwenden Sie die Benutzerdaten von früher.
f = open('qiita_users.csv', 'r')
reader = csv.reader(f)
next(reader)

qiita_tags = []
qiita_user_tags = []

#Ruft die Anzahl der CSV-Benutzerdaten ab. (Das erste Mal ist irrelevant)
if os.path.isfile('qiita_user_tags.csv'):
    user_tag_num = sum(1 for line in open('qiita_user_tags.csv'))
else:
    user_tag_num = 0

#Wenn Sie bereits über CSV-Tag-Daten verfügen, rufen Sie diese Tag-Daten ab (das erste Mal ist irrelevant).
if os.path.isfile('qiita_tags.csv'):
    f_tag = open('qiita_tags.csv', 'r')
    reader_tag = csv.reader(f_tag)
    qiita_tags = [tag[0] for tag in reader_tag]

#Öffnen Sie die CSV-Datei
f_tag = open('qiita_tags.csv', 'w')
writer_tag = csv.writer(f_tag, lineterminator='\n')
f_user_tag = open('qiita_user_tags.csv', 'a')
writer_user_tag = csv.writer(f_user_tag, lineterminator='\n')

#Klicken Sie auf die API für jeden Benutzer
for user in reader:
    if user_tag_num < int(user[0]):
        target_url = 'https://qiita.com/api/v1/users/' + user[1] + '/following_tags'
        print('scraping: ' + user[0])

        #Fehlerüberprüfung(Es gibt zwei Punkte: Die Anzahl der Anforderungen wird überschritten und der Benutzer existiert nicht.
        try:
            result = requests.get(target_url)
        except requests.exceptions.HTTPError as e:
            print(e)
            break
        target = result.json()

    #Geben Sie auf, wenn die Anzahl der Anfragen überschritten wird
        if 'error' in target:
            print(target['error'])
            if target['error'] == 'Rate limit exceeded.':
                break
            continue

        # user_id, tag_1, tag_2, ...Daten wie setzen
        qiita_user_tag = [int(user[0])]
        for tag in target:
            if tag['name'] in qiita_tags:
                qiita_user_tag.append(qiita_tags.index(tag['name']) + 1)
            else:
                qiita_tags.append(tag['name'])
                tag_num = len(qiita_tags)
                qiita_user_tag.append(tag_num)
        qiita_user_tags.append(qiita_user_tag)
        time.sleep(1) #Lassen Sie ein Intervall von 1 Sekunde, um eine Überlastung des Servers zu vermeiden

#Atme Daten in CSV aus
for tag in qiita_tags:
    writer_tag.writerow([tag])
writer_user_tag.writerows(qiita_user_tags)

f_tag.close()
f_user_tag.close()
f.close()

Unten finden Sie ein Ausgabebeispiel. Es gibt zwei CSV-Dateien, eine Tag-Datei und eine Benutzer-Tag-Beziehungsdatendatei. Die Zeilennummer des Tags ist die ID des Tags.

qiita_tags.csv


GoogleAppsScript
ActionScript
JavaScript
CSS
docker
...

qiita_user_tags.csv


1,1,2,3,4
2,5,6,7,3,8,9,10,11,12,13,14,15,16,17
3,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37
4,38,39,40,41,42,43,44,45,46,47,48,3,49
5,50,51,52,53,54,55,56,57,58,59,60,41,61,62,63,64,65,66,67,68
...

Daten bilden und auf Modelle anwenden

Wir werden die Daten und das Modell formen. Es kann mit der folgenden Datei ausgeführt werden, aber tatsächlich arbeite ich mit iPython Notebook. Es scheint auch, dass die Verwendung als Klasse vereinfacht werden kann, aber es reicht aus, wenn Sie den von Ihnen erstellten Ablauf kennen, sodass der Arbeitsablauf derselbe ist.

import csv
import gensim
from pandas import DataFrame

#Tag-ID(key)Und Name(value)Erstellen eines Wörterbuchs, das eine Verbindung herstellt
tag_name_dict = {}
with open('qiita_tags.csv', 'r') as f_tags:
    tag_reader = csv.reader(f_tags)

    for i, row in enumerate(tag_reader):
        tag_name_dict[(i+1)] = row[0]


#Welches Tag ein Benutzer (Schlüssel) verfolgt
user_tags_dict = {}
with open('qiita_user_tags.csv', 'r') as f_user_tags:
    user_tags_reader = csv.reader(f_user_tags)

    for i, row in enumerate(user_tags_reader):
        user_tags_dict[int(row[0])] = row[1:-1]

# tags_list Liste der Tags, denen gefolgt wird(Es gibt Duplikate, wenn mehrere Personen darauf folgen)
tags_list = []
for k, v in user_tags_dict.items():
    tags_list.extend(v)

#Tags, denen nur eine Person folgt
once_tags = [tag for tag in tags_list if tags_list.count(tag) == 1]

#Benutzer ein Tag, dem nur eine Person folgt_Auch aus Tags entfernt
user_tags_dict_multi = { k: [tag for tag in user_tags if not tag in once_tags] for k, user_tags in user_tags_dict.items()}

#Lassen Sie Benutzer aus, die keinen Tags folgen(Beachten Sie, dass wir Tags gelöscht haben, denen nur eine Person folgt)
user_tags_dict_multi = {k: v for k, v in user_tags_dict_multi.items() if not len(v) == 0}

#Zur Eingabe in gemsim konvertieren
corpus = [[(int(tag), 1) for tag in user_tags]for k, user_tags in user_tags_dict_multi.items()]

#Aufrufen und Lernen von LDA-Modellen Hier die Anzahl der Themen(Anzahl der Benutzergruppen) kann eingestellt werden
lda = gensim.models.ldamodel.LdaModel(corpus=corpus, num_topics=15)

#Holen Sie sich die Top-10-Auftrittshäufigkeit für jedes Thema
topic_top10_tags = []
for topic in lda.show_topics(-1, formatted=False):
    topic_top10_tags.append([tag_name_dict[int(tag[0])] for tag in topic[1]])

#Zeigen Sie die 10 am häufigsten auftretenden Themen an
topic_data = DataFrame(topic_top10_tags)
print(topic_data)
print("------------------")

#Anzeige der Benutzereinstellungen
c = [(1, 1), (2, 1)] #Benutzer, die Tag 1 und Tag 2 folgen
for (tpc, prob) in lda.get_document_topics(c):
    print(str(tpc) + ': '+str(prob))

Ergebnis

Unten finden Sie eine Gruppe von Wörtern für jedes Thema. (Ich habe das Display des iPython-Notebooks verwendet) Jede Zeile repräsentiert jedes Thema. Es wurde in 15 Benutzergruppen unterteilt, z. B. Benutzergruppe Zeile 0, Benutzerschicht Zeile 1 usw.

スクリーンショット 2016-09-07 22.44.17.png

Zu welchem Thema gehört der Benutzer, der Tag 1 und Tag 2 folgt? Es sieht aus wie "7". Ich habe es diesmal richtig eingegeben, aber wenn Sie das Tag, dem Sie folgen, als Eingabedaten verwenden, können Sie möglicherweise sehen, welche Art von Benutzergruppe Sie sind. Wenn Sie dies verwenden, können Sie anscheinend auch Tags empfehlen.

0: 0.0222222589596
1: 0.0222222222222
2: 0.0222222417019
3: 0.0222222755597
4: 0.022222240412
5: 0.0222222222222
6: 0.0222222374859
7: 0.688888678865
8: 0.02222225339
9: 0.0222222557189
10: 0.0222222222222
11: 0.0222222222222
12: 0.0222222222222
13: 0.0222222245736
14: 0.0222222222222

Bonus: Das Folgende ist eine Version mit 20 Themen. Ich habe das Gefühl, dass 20 Teile anfälliger zu sein scheinen. スクリーンショット 2016-09-07 22.45.19.png

Es scheint, dass verschiedene Dinge gesehen werden können, indem die Anzahl der Daten erhöht und die Anzahl der Themen geändert wird.

Am Ende

Ich hoffe, dies ist der Katalysator für alle, die sich für das Themenmodell interessieren. Ich werde selbst mehr lernen.

Recommended Posts

Themenmodell von LDA mit Gensim ~ Nachdenken über den Geschmack des Benutzers vom Qiita-Tag ~
Stock Number Ranking von Qiita Tag mit Python