[PYTHON] Netzwerkanalyse von Sprachschauspielern (mit word2vec und networkx) (1/2)

Der in diesem Artikel eingeführte grobe Fluss

・ Eine Liste der Namen und Geschlechter der Sprecher erstellen und abrufen ・ Trennen Sie die Textinformationen der Wikipedia des Synchronsprechers, die in der Liste enthalten sind, mit mecab und lernen Sie mit word2vec ・ Spielen Sie mit der Wortanalyse mit dem mit word2vec erlernten Modell

Grober Analysefluss, der beim nächsten Mal eingeführt werden soll

・ Erstellen und visualisieren Sie ein Netzwerk für weibliche Sprecher ・ Verwenden Sie Netzwerkinformationen, um ähnliche Sprachakteure zu gruppieren und zu kategorisieren

Schön dich kennenzulernen, mein Name ist Bambus-Nova. Qiita wird hauptsächlich ** Materialanalyse ** einwerfen. Weitere Informationen und Analysen finden Sie im "Hatena-Blog". Außerdem ist NLP überhaupt keine Spezialität, daher denke ich, dass es ein kindischer Code ist, aber bitte schauen Sie mit warmen Augen zu ...!

http://yukr.hatenablog.com/

Dies ist der erste Beitrag, aber ich habe ** Voice Actor Network Analysis ** als erste Materialanalyse ausprobiert.

Dieses Mal brachte ich den Wikipedia-Artikel eines Synchronsprechers mit, erstellte aus den dortigen Textinformationen ein Netzwerk ähnlicher oder verwandter Synchronsprecher und beschloss, von dort aus weitere Cluster zu erstellen.

Dieses Mal werden wir ein Lernmodell erstellen und es nur für weibliche Sprecher im Alter von Teenagern und 30 Jahren analysieren.

** Ergänzung) ** Ich habe den Quellcode, der die bisherige Reihe von Schritten auf Github zusammenfasst, auf ihn bezogen.

bamboo-nova/seiyu_network

Holen Sie sich zunächst eine Liste der weiblichen Sprecher.

Verschrotten Sie die folgenden Websites, um eine Liste der Namen der Sprecher zu erhalten. Es scheint, dass Sprachschauspieler, deren Alter nicht bekannt gegeben wird, nicht in der Liste auf dieser Website enthalten sind. Selbst wenn sie berühmt sind, werden sie möglicherweise nicht in der Analyse angezeigt.

http://lain.gr.jp/voicedb/individual

Rufen Sie zunächst das gewünschte Modul auf.

import MeCab
import codecs
import urllib
import urllib.parse as parser
import urllib.request as request
import requests
from bs4 import BeautifulSoup
import numpy as np
import pandas as pd

from gensim.models import word2vec

import re

# .Ich habe es in diejenigen unterteilt, die parseToNode ausführen, und diejenigen, die dies nicht tun.
mecab = MeCab.Tagger('-Owakati -d /usr/local/mecab/lib/mecab/dic/mecab-ipadic-neologd')
title = MeCab.Tagger('-d /usr/local/mecab/lib/mecab/dic/mecab-ipadic-neologd')

Ruft die Informationen der angegebenen URL ab.

url = "http://lain.gr.jp/voicedb/individual/age/avg/10"
 
response = requests.get(url)
response.encoding = response.apparent_encoding
 
soup10 = BeautifulSoup(response.text, 'html.parser')
 
url = "http://lain.gr.jp/voicedb/individual/age/avg/20"
 
response = requests.get(url)
response.encoding = response.apparent_encoding
 
soup20 = BeautifulSoup(response.text, 'html.parser')

url = "http://lain.gr.jp/voicedb/individual/age/avg/30"
 
response = requests.get(url)
response.encoding = response.apparent_encoding
 
soup30 = BeautifulSoup(response.text, 'html.parser')

Erhalten Sie zuerst den Namen des Synchronsprechers. Dieses Mal werden in der URL des obigen Quellcodes alle Tags mit dem href-Attribut einschließlich "voicedb / profile" von Sprachschauspielern im Alter von Teenagern und 30 Jahren erfasst. Das folgende Bild zeigt, wann eine der URLs des obigen Quellcodes tatsächlich mit Chrome überprüft wurde, der Name des Sprachschauspielers jedoch tatsächlich in einem Listenformat im href-Attribut einschließlich "voicedb / profile" gespeichert ist. Ich denke, Sie können das bestätigen.

スクリーンショット 2020-02-07 16.30.48.png

Unten der Quellcode, um den Namen zu erhalten

corpus=[]
name10 = soup10.find_all(href=re.compile("voicedb/profile"))
name20 = soup20.find_all(href=re.compile("voicedb/profile"))
name30 = soup30.find_all(href=re.compile("voicedb/profile"))
for p in name10:
            corpus.append(p.text)
for p in name20:
            corpus.append(p.text)
for p in name30:
            corpus.append(p.text)

Dann holen Sie sich das Geschlecht. Wenn Sie sich das oben verifizierte Bild ansehen, scheint es in Ordnung zu sein, src und alt im img-Tag abzurufen. Rufen Sie es also wie folgt auf. Übrigens wird der Teil von "alt = img.attrs.get (" alt "," N ")" auf seinen Wert gesetzt, wenn das alt-Attribut existiert, und "N", wenn es nicht existiert.

data = []
for img in soup10.find_all('img'):
    data.append(dict(src=img['src'],
                     alt=img.attrs.get('alt', 'N')))
for img in soup20.find_all('img'):
    data.append(dict(src=img['src'],
                     alt=img.attrs.get('alt', 'N')))
for img in soup30.find_all('img'):
    data.append(dict(src=img['src'],
                     alt=img.attrs.get('alt', 'N')))

gender = []
for res in data:
    for k, v in res.items():
        if v == 'Weiblich' or v == 'männlich':
            gender.append(v)

Speichern Sie dann den Datenrahmen, der den Namen und das Geschlecht im CSV-Format integriert.

name = pd.DataFrame(corpus)
gen = pd.DataFrame(gender)
res = pd.concat([name, gen],axis=1)
res.columns = ['Name','Gender']
res.to_csv('seiyu.csv')

Holen Sie sich die Profilinformationen von Wikipedia der Sprecherin, die in der erhaltenen Liste enthalten sind.

Wählen Sie nun nur weibliche Sprecher aus den gespeicherten Datenrahmen aus und erhalten Sie die Profilinformationen des Zielsprachers auf Wikipedia. Die erhaltenen Informationen werden als pwiki.txt gespeichert.

df = pd.read_csv('seiyu.csv')

#Wikipedia-Link
link = "https://ja.wikipedia.org/wiki/"
#Richten Sie sich nur an weibliche Sprecher
df_women = df[df.Gender=='Weiblich']
keyword = df_women.Name
keyword = list(keyword)
corpus = []
for word in keyword:
    #Sprachschauspieler-Artikel herunterladen
    try:
        with request.urlopen(link + parser.quote_plus(word)) as response:
            #Die Antwort ist im HTML-Format
            html = response.read().decode('utf-8')
            soup = BeautifulSoup(html, "lxml")
            # <p>Tag holen
            p_tags = soup.find_all('p')
            for p in p_tags:
                corpus.append(p.text.strip())
    except urllib.error.HTTPError as err:
        #Bei Sprachschauspielern, die nicht in Wikipedia aufgeführt sind, tritt ein Fehler auf, sodass die Ausnahmebehandlung hinzugefügt wird.
        if err.code == 404:
            continue
        else:
            raise

with codecs.open("pwiki.txt", "w", "utf-8") as f:
    f.write("\n".join(corpus))

Teilen Sie die Textdatei und speichern Sie das Trainingsmodell als word2vec.

Schreiben wir nun die tatsächlich erfassten Textdaten auf. Da es diesmal viele Namen von Animationen gibt, unterstützen wir auch die richtige Nomenklatur (zum Beispiel wird die High-School-Flotte als richtige Nomenklatur und Organisation behandelt, wenn Sie also normalerweise ParseToNode * verwenden. Wird sein). Wie im folgenden Beispiel gezeigt, scheint ** aus irgendeinem Grund, wenn Sie "precure" separat mit mecab + neologd schreiben, in Englisch konvertiert zu werden **, antworten Sie also auch mit dem bedingten Zweig der if-Anweisung, damit es auf Englisch reagiert. (Da es so viele Sprachschauspieler gab, die ihr Erscheinen in Precure in ihrem Profil als Status veröffentlicht haben, konnte es nicht als Informationen zur Funktionsmenge ignoriert werden. Deshalb habe ich es so gestaltet, dass die Aufteilung richtig wiedergegeben wird.)

node = title.parse('Präzise')

node.split(",")[6]
#Ausgabeergebnis: 'PulCheR'

Unten ist der tatsächliche Quellcode. Verarbeiten Sie zunächst die Textdaten vor.

fi = codecs.open('pwiki.txt')
result = []
fo = open('try.csv', 'w')

lines = fi.readlines()
for line in lines:
    line = re.sub('[\n\r]',"",line)
    line = re.sub('[ ]'," ",line) #Einige Nomenklaturen können nicht als zusammengesetzte Nomenklaturen extrahiert werden, es sei denn, der Raum voller Breite wird in die halbe Breite umgewandelt.
    line = re.sub('(Jahr|Mond|Tag)',"",line)
    line = re.sub('[0-9_]',"",line)
    line = re.sub('[#]',"",line)
    line = re.sub('[!]',"",line)
    line = re.sub('[*]',"",line)
    fo.write(line + '\n')


fi.close()
fo.close()

Dann werden die vorverarbeiteten Textdaten tatsächlich geteilt und mit word2vec gelernt. Diesmal habe ich mit den Standardparametern gelernt. Die Erklärung von word2vec wird hier weggelassen. Den Mechanismus usw. finden Sie unter der folgenden URL.

Word2Vec: Die erstaunliche Kraft des Wortvektors, die selbst der Erfinder überrascht

fi = open('try.csv', 'r')
fo = open('res.csv', 'w')

#line = fi.readline()
lines = fi.readlines()
result=[]
mecab.parse("")


for line in lines:
    node = mecab.parseToNode(line)
    node_org = title.parse(line)
    
    while node:
        hinshi = node.feature.split(",")[0]
        if hinshi == 'Adjektiv' or hinshi == 'Substantiv' or hinshi == 'Adverb' or (len(node.feature.split(",")[6])>1):
            fo.write(node.feature.split(",")[6] + ' ')
        if node_org != 'EOS\n' and node_org.split(",")[1] == 'Proprietäre Nomenklatur':
            fo.write(node_org.split(",")[6] + ' ')
        if node_org != 'EOS\n' and node_org.split(",")[1] == 'Proprietäre Nomenklatur' and node_org.split(",")[6].isalpha()==True:
            fo.write(node_org.split(",")[7] + ' ')
        node = node.next

fi.close()
fo.close()

print('Wakati phase completed!')

sentences = word2vec.LineSentence('res.csv')
model = word2vec.Word2Vec(sentences,
                          sg=1,
                          size=200,
                          min_count=5,
                          window=5,
                          hs=1,
                          iter=100,
                          negative=0)


#Mit Gurke speichern
import pickle
with open('mecab_word2vec_seiyu.dump', mode='wb') as f:
    pickle.dump(model, f)

Probieren Sie die Ergebnisse des word2vec-Modells aus

Spielen wir mit der Wortanalyse unter Verwendung des Modells, das tatsächlich mit word2vec gelernt wurde. Als Test werde ich versuchen, sogar einen Synchronsprecher herauszubringen, der sich nicht als Idol zu verkaufen scheint.

ret = model.wv.most_similar(negative=['Idol'],topn=1000) 

for item in ret:
    if len(item[0])>2 and (item[0] in list(df.Name)):
        print(item[0],item[1])

Ausgabeergebnis

Sumi Nako 0.13453319668769836
Shota Aoi 0.1175239235162735
Aio Toyosaki 0.1002458706498146
Tomoka Tamura 0.08929911255836487
Akane Yamaguchi 0.05830669403076172
Ayaka Mori 0.056574173271656036
Saki Fujita 0.05241834372282028
Yui Kano 0.051871318370103836
Saori Hayami 0.04932212829589844
Mika Kikuchi 0.04044754058122635
Anzu Suzuki 0.034879475831985474
Ryota Osaka 0.029612917453050613
Yuka Iguchi 0.02767171896994114
Aoki Yuki 0.02525651454925537
Chieko Higuchi 0.022603293880820274

Als nächstes werde ich einen Synchronsprecher herausnehmen, der eine starke Idolfarbe zu haben scheint.

ret = model.wv.most_similar(positive=['Idol'],topn=300) 

for item in ret:
    if len(item[0])>2 and (item[0] in list(df.Name)):
        print(item[0],item[1])

Ausgabeergebnis

Machico 0.1847614347934723
Kaori Fukuhara 0.1714700609445572
Sachika Misawa 0.1615515947341919
Mai Nakahara 0.15694507956504822
Yui Ogura 0.1562490165233612
Shoko Nakagawa 0.1536223590373993
Nao Higashiyama 0.15278896689414978
Yui Sakakibara 0.14662891626358032
Ai Shimizu 0.14592087268829346
Natsuori Ishihara 0.14554426074028015

Als nächstes extrahieren wir die Sprecher, die wahrscheinlich einen Zusammenhang mit der "Auszeichnung" haben.

ret = model.wv.most_similar(positive=['Vergeben'],topn=500) 

for item in ret:
    if len(item[0])>2 and (item[0] in list(df.Name)):
        print(item[0],item[1])

Ausgabeergebnis


Kido Ibuki 0.19377963244915009
Kaori Fukuhara 0.16889861226081848
Minami Tsuda 0.16868139803409576
Shinrei Uchida 0.1677364706993103
Kaori Nazuka 0.1669023633003235
Ai Chino 0.16403883695602417
Maaya Sakamoto 0.16285887360572815
Yui Makino 0.14633819460868835
Ellie Yamazaki 0.1392231583595276
Eri Kitamura 0.13390754163265228
Kana Asumi 0.13131362199783325
Arisa Noto 0.13084736466407776
Ayaka Ohashi 0.1297467052936554
Ryota Osaka 0.12972146272659302

Ah, ich frage mich ... ich habe das Gefühl, dass es wirklich so ist (** Übrigens, selbst wenn ich "Ehe" sage, kam es heraus lol **).

Zusammenfassung

Dieses Mal erhielt ich die Informationen aus der Wikipedia des Synchronsprechers, speicherte das Lernmodell mit word2vec unter Verwendung der erhaltenen Textinformationen und versuchte, das Modell tatsächlich zu verschieben. Da die Textinformationen des Profils auf Wikipedia begrenzt sind, weil keine detaillierten Informationen vorhanden sind, müssen große Datenmengen und Modelle überprüft werden, um sie tatsächlich ernsthaft analysieren zu können. Bitte verzeihen Sie mir jedoch, da ich hier nur zur Materialanalyse poste. ** Tatsächlich ist die Menge der Textdaten gering und das Ergebnis ändert sich geringfügig in Abhängigkeit vom Parameter von word2vec, sodass es möglicherweise nicht genau das Ergebnis des Blogs ist **. Das allgemeine Ergebnis selbst ändert sich nicht so dramatisch, aber ... Schweiß

Als nächstes werden wir es als Netzwerk anhand des tatsächlich erlernten Modells visualisieren und das Netzwerk tatsächlich gruppieren, um ähnliche Sprachschauspieler zu kategorisieren.

Recommended Posts

Netzwerkanalyse von Sprachschauspielern (mit word2vec und networkx) (1/2)
Netzwerkanalyse von Sprachschauspielern (mit word2vec und networkx) (2/2)
Netzwerkanalyse mit NetworkX --- Community-Erkennungsvolumen
Globale Sensitivitätsanalyse unter Verwendung der Sensitivitätsanalysebibliotheken Salib und Oacis
Autorenschätzung unter Verwendung von neuronalen Netzen und Doc2Vec (Aozora Bunko)