In diesem Artikel werde ich Ihnen zeigen, wie Sie mit Wordcloud visualisieren, welche Themen in der Slack-Community über einen bestimmten Zeitraum (1 Woche hier) angesprochen wurden.
Den Quellcode finden Sie hier: octocat:
Ich möchte auch lesen: [Verarbeitung natürlicher Sprache] Ich habe versucht, die Bemerkungen jedes Mitglieds in der Slack-Community zu visualisieren
* Ich möchte die Vorverarbeitung in Zukunft in einem anderen Artikel zusammenfassen </ font>
Weitere Informationen finden Sie unter Erste Schritte in README. Der Fluss ist so.
run_wordcloud_by_term.sh
ausDies ist ein Beispiel für die tatsächliche Ausgabe. Wordcloud ist die Bemerkung jeder einzelnen Periode.
Erhalten Sie Slack API-Token von Slack API Official
Wie Sie mit der Slack-API beginnen, wird hier nicht gezeigt.
Um die nachfolgende Verarbeitung durchzuführen, besorgen Sie sich bitte die folgenden Token
Hier erstellen wir eine ** SlackApp ** -Klasse, die Slack-Informationen über die API abruft. Die erfassten Informationen werden ohne Verarbeitung im JSON-Format gespeichert.
slack_app.py
#Eine Klasse, die Slackapi verwendet, um die gewünschten Informationen zu erhalten(Nicht verarbeiten)
import requests
import json
from tqdm import tqdm
import pandas as pd
class SlackApp:
ch_list_url = 'https://slack.com/api/channels.list'
ch_history_url = 'https://slack.com/api/channels.history'
usr_list_url = 'https://slack.com/api/users.list'
def __init__(self, ch_api_key, usr_api_key):
# NEW members
self.channels_info = []
self.users_info = []
self.messages_info = []
# OLD members
self.channelInfo = {} # k: ch_name, v: ch_id
self.messages_in_chs = {}
self.userInfo = {}
self.ch_api_token = str(ch_api_key)
self.usr_api_token = str(usr_api_key)
def load_save_channel_info(self, outdir: str):
#Holen Sie sich Kanalinformationen über die Slack-API und speichern Sie sie in einer Datei
payload = {'token': self.ch_api_token}
response = requests.get(SlackApp.ch_list_url, params=payload)
if response.status_code == 200:
json_data = response.json()
if 'channels' in json_data.keys():
self.channels_info = json_data['channels']
with open(outdir + '/' + 'channel_info.json', 'w', encoding='utf-8') as f:
json.dump(self.channels_info, f, indent=4, ensure_ascii=False)
def load_save_user_info(self, outdir: str):
#Holen Sie sich Benutzerinformationen über die Slack-API und speichern Sie sie in einer Datei
payload = {'token': self.usr_api_token}
response = requests.get(SlackApp.usr_list_url, params=payload)
if response.status_code == 200:
json_data = response.json()
if 'members' in json_data.keys():
self.users_info = json_data['members']
with open(outdir + '/' + 'user_info.json', 'w', encoding='utf-8') as f:
json.dump(self.users_info, f, indent=4, ensure_ascii=False)
def load_save_messages_info(self, outdir: str):
#Erstellen Sie eine Kanal-ID-Liste
channel_id_list = []
for ch in self.channels_info:
channel_id_list.append(ch['id'])
#Holen Sie sich Benutzerinformationen über die Slack-API und speichern Sie sie in einer Datei
for ch_id in tqdm(channel_id_list, desc='[loading...]'):
payload = {'token': self.ch_api_token, 'channel': ch_id}
response = requests.get(SlackApp.ch_history_url, params=payload)
if response.status_code == 200:
json_data = response.json()
msg_in_ch = {}
msg_in_ch['channel_id'] = ch_id
if 'messages' in json_data.keys():
msg_in_ch['messages'] = json_data['messages']
else:
msg_in_ch['messages'] = ''
self.messages_info.append(msg_in_ch)
with open(outdir + '/' + 'messages_info.json', 'w', encoding='utf-8') as f:
json.dump(self.messages_info, f, indent=4, ensure_ascii=False)
Verwenden Sie die Klasse ** SlackApp ** früher, um die Informationen abzurufen.
Die zu erfassenden Informationen sind die folgenden drei
slack_msg_extraction.py
#Eine Klasse, die Slackapi verwendet, um die gewünschten Informationen zu erhalten
import sys
import json
sys.path.append('../../src/d000_utils') #Speicherpfad für SlackApp-Skripte hinzugefügt
import slack_app as sa
def main():
# -------------------------------------
# load api token
# -------------------------------------
credentials_root = '../../conf/local/'
credential_fpath = credentials_root + 'credentials.json'
print('load credential.json ...')
with open(credential_fpath, 'r') as f:
credentials = json.load(f)
# -------------------------------------
# start slack app
# -------------------------------------
print('start slack app ...')
app = sa.SlackApp(
credentials['channel_api_key'],
credentials['user_api_key']
)
outdir = '../../data/010_raw'
# -------------------------------------
# get channels info
# -------------------------------------
app.load_save_channel_info(outdir)
# -------------------------------------
# get user info
# -------------------------------------
app.load_save_user_info(outdir)
# -------------------------------------
# get msg info
# -------------------------------------
app.load_save_messages_info(outdir)
if __name__ == "__main__":
main()
Die von SlackAPI erfassten Informationen wurden gemäß den Spezifikationen von SlackAPI im JSON-Format gespeichert. Formatieren Sie die Tabellendaten so, dass sie leicht analysiert werden können. Beachten Sie beim Entwerfen einer Tabelle Tidy Data.
Dieses Mal habe ich es wie folgt gestaltet. Die folgende Tabelle basiert auf dem Bild der minimal erforderlichen Informationen + α.
message mart table
No | Column Name | Type | Content |
---|---|---|---|
0 | index | int | AUTO INCREMENT |
1 | ch_id | str | Kanal ID |
2 | msg | str | Nachrichtenzeichenfolge |
3 | uid | str | Benutzer-ID des Sprechers |
4 | timestamp | datetime | Zeit zu sprechen |
No | Column Name | Type | Content |
---|---|---|---|
0 | index | int | AUTO INCREMENT |
1 | ch_id | str | Kanal ID |
2 | ch_name | str | Kanalname (Name wird auf der Slack-Benutzeroberfläche angezeigt) |
3 | ch_namenorm | str | Normalisierter Kanalname |
4 | ch_membernum | int | Anzahl der Teilnehmer im Kanal |
No | Column Name | Type | Content |
---|---|---|---|
0 | index | int | AUTO INCREMENT |
1 | uid | str | Benutzeridentifikation |
2 | uname | str | Nutzername |
Der tatsächliche Code ist unten.
../../ data / 010_raw
: Informationen, die vom Speicherort im Slack JSON-Format abgerufen wurden
--user_info.json
: JSON-Dateiname (User Information)
--messages_info.json
: JSON-Dateiname (Message Information) für alle Kanäle
--channel_info.json
: Name der JSON-Datei (Channel Information)make_msg_mart_table.py
import json
import pandas as pd
def make_user_table(usr_dict: dict) -> pd.DataFrame:
uid_list = []
uname_list = []
for usr_ditem in usr_dict:
if usr_ditem['deleted'] == True:
continue
uid_list.append(usr_ditem['id'])
uname_list.append(usr_ditem['profile']['real_name_normalized'])
user_table = pd.DataFrame({'uid': uid_list, 'uname': uname_list})
return user_table
def make_msg_table(msg_dict: dict) -> pd.DataFrame:
ch_id_list = []
msg_list = []
uid_list = []
ts_list = []
for msg_ditem in msg_dict:
if 'channel_id' in msg_ditem.keys():
ch_id = msg_ditem['channel_id']
else:
continue
if 'messages' in msg_ditem.keys():
msgs_in_ch = msg_ditem['messages']
else:
continue
# get message in channel
for i, msg in enumerate(msgs_in_ch):
# if msg by bot, continue
if 'user' not in msg:
continue
ch_id_list.append(ch_id)
msg_list.append(msg['text'])
uid_list.append(msg['user']) #Es gibt keinen Schlüssel für Bot
ts_list.append(msg['ts'])
df_msgs = pd.DataFrame({
'ch_id': ch_id_list,
'msg': msg_list,
'uid': uid_list,
'timestamp': ts_list
})
return df_msgs
def make_ch_table(ch_dict: dict) -> pd.DataFrame:
chid_list = []
chname_list = []
chnormname_list = []
chmembernum_list = []
for ch_ditem in ch_dict:
chid_list.append(ch_ditem['id'])
chname_list.append(ch_ditem['name'])
chnormname_list.append(ch_ditem['name_normalized'])
chmembernum_list.append(ch_ditem['num_members'])
ch_table = pd.DataFrame({
'ch_id': chid_list,
'ch_name': chname_list,
'ch_namenorm': chnormname_list,
'ch_membernum': chmembernum_list
})
return ch_table
def main():
# 1. load user/message/channels
input_root = '../../data/010_raw'
user_info_fpath = input_root + '/' + 'user_info.json'
with open(user_info_fpath, 'r', encoding='utf-8') as f:
user_info_rawdict = json.load(f)
print('load ... ', user_info_fpath)
msg_info_fpath = input_root + '/' + 'messages_info.json'
with open(msg_info_fpath, 'r', encoding='utf-8') as f:
msgs_info_rawdict = json.load(f)
print('load ... ', msg_info_fpath)
ch_info_fpath = input_root + '/' + 'channel_info.json'
with open(ch_info_fpath, 'r', encoding='utf-8') as f:
ch_info_rawdict = json.load(f)
print('load ... ', ch_info_fpath)
# 2. make and save tables
# user
output_root = '../../data/020_intermediate'
df_user_info = make_user_table(user_info_rawdict)
user_tbl_fpath = output_root + '/' + 'users.csv'
df_user_info.to_csv(user_tbl_fpath, index=False)
print('save ... ', user_tbl_fpath)
# msg
df_msg_info = make_msg_table(msgs_info_rawdict)
msg_tbl_fpath = output_root + '/' + 'messages.csv'
df_msg_info.to_csv(msg_tbl_fpath, index=False)
print('save ... ', msg_tbl_fpath)
# channel
df_ch_info = make_ch_table(ch_info_rawdict)
ch_tbl_fpath = output_root + '/' + 'channels.csv'
df_ch_info.to_csv(ch_tbl_fpath, index=False)
print('save ... ', ch_tbl_fpath)
if __name__ == "__main__":
main()
Bezieht sich im Allgemeinen auf das Entfernen von Rauschen Abhängig von den Zieldaten und dem Zweck müssen verschiedene Verarbeitungen durchgeführt werden. Hier wurde die folgende Verarbeitung ausgeführt.
cleaning.py
import re
import pandas as pd
import argparse
from pathlib import Path
def clean_msg(msg: str) -> str:
# sub 'Return and Space'
result = re.sub(r'\s', '', msg)
# sub 'url link'
result = re.sub(r'(<)http.+(>)', '', result)
# sub 'mention'
result = re.sub(r'(<)@.+\w(>)', '', result)
# sub 'reaction'
result = re.sub(r'(:).+\w(:)', '', result)
# sub 'html key words'
result = re.sub(r'(&).+?\w(;)', '', result)
# sub 'multi lines code block'
result = re.sub(r'(```).+(```)', '', result)
# sub 'inline code block'
result = re.sub(r'(`).+(`)', '', result)
return result
def clean_msg_ser(msg_ser: pd.Series) -> pd.Series:
cleaned_msg_list = []
for i, msg in enumerate(msg_ser):
cleaned_msg = clean_msg(str(msg))
if 'Ist dem Kanal beigetreten' in cleaned_msg:
continue
cleaned_msg_list.append(cleaned_msg)
cleaned_msg_ser = pd.Series(cleaned_msg_list)
return cleaned_msg_ser
def get_ch_id_from_table(ch_name_parts: list, input_fpath: str) -> list:
df_ch = pd.read_csv(input_fpath)
ch_id = []
for ch_name_part in ch_name_parts:
for i, row in df_ch.iterrows():
if ch_name_part in row.ch_name:
ch_id.append(row.ch_id)
break
return ch_id
def main(input_fname: str):
input_root = '../../data/020_intermediate'
output_root = input_root
# 1. load messages.csv (including noise)
msgs_fpath = input_root + '/' + input_fname
df_msgs = pd.read_csv(msgs_fpath)
print('load :{0}'.format(msgs_fpath))
# 2. Drop Not Target Records
print('drop records (drop non-target channel\'s messages)')
non_target_ch_name = ['general', 'Ankündigung des Managements']
non_target_ch_ids = get_ch_id_from_table(non_target_ch_name, input_root + '/' + 'channels.csv')
print('=== non target channels bellow ====')
print(non_target_ch_ids)
for non_target_ch_id in non_target_ch_ids:
df_msgs = df_msgs.query('ch_id != @non_target_ch_id')
# 3. clean message string list
ser_msg = df_msgs.msg
df_msgs.msg = clean_msg_ser(ser_msg)
# 4. save it
pin = Path(msgs_fpath)
msgs_cleaned_fpath = output_root + '/' + pin.stem + '_cleaned.csv'
df_msgs.to_csv(msgs_cleaned_fpath, index=False)
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("input_fname", help="set input file name", type=str)
args = parser.parse_args()
input_fname = args.input_fname
main(input_fname)
Eigentlich wollte ich "nur entfernen, wenn der Codeblock Quellcode enthält", konnte es aber nicht. : Schweiß:
Im Allgemeinen ist es der Prozess, "Morphologie" in einem Satz zu finden. Details der morphologischen Analyse werden anderen Artikeln überlassen.
Der eigentliche Zweck hier ist das "Teilen".
Grob gesagt ist es der Prozess, einen Satz in Informationen umzuwandeln, die als "Wort Wort Wort" bezeichnet werden. Zum Beispiel
** Beispielsatz: Ich mag Baseball. ** **. ** Beispielsatzsegmentierung: "Ich mag Baseball" **
Es wird in Form von sein.
In der Praxis ist es vorzuziehen, "Nomen" </ font> zu extrahieren, wenn Sie mit Wörtern umgehen möchten, die den Kontext eines Satzes wie dieses Mal darstellen. Deshalb,
** Trennung von Beispielsätzen (nur Nomenklatur): "Private Baseball" **
Es wäre noch besser.
Wenn Sie eine morphologische Analyse implementieren möchten
Das müssen wir entscheiden.
Dieses Mal habe ich Folgendes getan.
Darüber hinaus sind die zu extrahierenden Teilwörter diejenigen, die zur Erreichung des Zwecks erforderlich sind, während ein Blick auf "Teilteilsystem des morphologischen Analysewerkzeugs" geworfen wird. etwas? Dachte ich aus der Sicht.
Janome, das offizielle Maskottchen, ist süß. (Ich weiß nicht, ob Janome der Name ist)
morphological_analysis.py
from janome.tokenizer import Tokenizer
from tqdm import tqdm
import pandas as pd
import argparse
from pathlib import Path
import sys
exc_part_of_speech = {
"Substantiv": ["Nicht unabhängig", "代Substantiv", "Nummer"]
}
inc_part_of_speech = {
"Substantiv": ["Verbindung ändern", "Allgemeines", "固有Substantiv"],
}
class MorphologicalAnalysis:
def __init__(self):
self.janome_tokenizer = Tokenizer()
def tokenize_janome(self, line: str) -> list:
# list of janome.tokenizer.Token
tokens = self.janome_tokenizer.tokenize(line)
return tokens
def exists_pos_in_dict(self, pos0: str, pos1: str, pos_dict: dict) -> bool:
# Retrurn where pos0, pos1 are in pos_dict or not.
# ** pos = part of speech
for type0 in pos_dict.keys():
if pos0 == type0:
for type1 in pos_dict[type0]:
if pos1 == type1:
return True
return False
def get_wakati_str(self, line: str, exclude_pos: dict,
include_pos: dict) -> str:
'''
exclude/include_pos is like this
{"Substantiv": ["Nicht unabhängig", "代Substantiv", "Nummer"], "Adjektiv": ["xxx", "yyy"]}
'''
tokens = self.janome_tokenizer.tokenize(line, stream=True) #Generator zum Speichern von Speicher
extracted_words = []
for token in tokens:
part_of_speech0 = token.part_of_speech.split(',')[0]
part_of_speech1 = token.part_of_speech.split(',')[1]
# check for excluding words
exists = self.exists_pos_in_dict(part_of_speech0, part_of_speech1,
exclude_pos)
if exists:
continue
# check for including words
exists = self.exists_pos_in_dict(part_of_speech0, part_of_speech1,
include_pos)
if not exists:
continue
# append(Erworbene Oberflächenschichtform zur Absorption von Notationsschwankungen)
extracted_words.append(token.surface)
# wakati string with extracted words
wakati_str = ' '.join(extracted_words)
return wakati_str
def make_wakati_for_lines(msg_ser: pd.Series) -> pd.Series:
manalyzer = MorphologicalAnalysis()
wakati_msg_list = []
for msg in tqdm(msg_ser, desc='[mk wakati msgs]'):
wakati_msg = manalyzer.get_wakati_str(str(msg), exc_part_of_speech,
inc_part_of_speech)
wakati_msg_list.append(wakati_msg)
wakati_msg_ser = pd.Series(wakati_msg_list)
return wakati_msg_ser
def main(input_fname: str):
input_root = '../../data/020_intermediate'
output_root = '../../data/030_processed'
# 1. load messages_cleaned.csv
msgs_cleaned_fpath = input_root + '/' + input_fname
df_msgs = pd.read_csv(msgs_cleaned_fpath)
# 2. make wakati string by record
ser_msg = df_msgs.msg
df_msgs['wakati_msg'] = make_wakati_for_lines(ser_msg)
# 3. save it
pin = Path(msgs_cleaned_fpath)
msgs_wakati_fpath = output_root + '/' + pin.stem + '_wakati.csv'
df_msgs.to_csv(msgs_wakati_fpath, index=False)
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("input_fname", help="set input file name", type=str)
args = parser.parse_args()
input_fname = args.input_fname
# input file must been cleaned
if 'cleaned' not in input_fname:
print('input file name is invalid.: {0}'.format(input_fname))
print('input file name must include \'cleaned\'')
sys.exit(1)
main(input_fname)
Die Normalisierung bei der Vorverarbeitung der Verarbeitung natürlicher Sprache bezieht sich auf die folgende Verarbeitung. Es wird auch "Namensidentifikation" genannt.
Die Welt der Normalisierung ist tief, also lasse ich sie hier.
Dieses Mal wurde der Einfachheit halber nur die folgende Verarbeitung implementiert. Es ist wahnsinnig einfach.
normalization.py
import re
import pandas as pd
from tqdm import tqdm
import argparse
from pathlib import Path
import sys
def normarize_text(text: str):
normalized_text = normalize_number(text)
normalized_text = lower_text(normalized_text)
return normalized_text
def normalize_number(text: str) -> str:
"""
pattern = r'\d+'
replacer = re.compile(pattern)
result = replacer.sub('0', text)
"""
#Ersetzen Sie fortlaufende Zahlen durch 0
replaced_text = re.sub(r'\d+', '0', text)
return replaced_text
def lower_text(text: str) -> str:
return text.lower()
def normalize_msgs(wktmsg_ser: pd.Series) -> pd.Series:
normalized_msg_list = []
for wktstr in tqdm(wktmsg_ser, desc='normalize words...'):
normalized = normarize_text(str(wktstr))
normalized_msg_list.append(normalized)
normalized_msg_ser = pd.Series(normalized_msg_list)
return normalized_msg_ser
def main(input_fname: str):
input_root = '../../data/030_processed'
output_root = input_root
# 1. load wakati messages
msgs_fpath = input_root + '/' + input_fname
df_msgs = pd.read_csv(msgs_fpath)
# 2. normalize wakati_msg (update)
ser_msg = df_msgs.wakati_msg
df_msgs.wakati_msg = normalize_msgs(ser_msg)
# 3. save it
pin = Path(msgs_fpath)
msgs_ofpath = output_root + '/' + pin.stem + '_norm.csv'
df_msgs.to_csv(msgs_ofpath, index=False)
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("input_fname", help="set input file name", type=str)
args = parser.parse_args()
input_fname = args.input_fname
# input file must been cleaned
if 'wakati' not in input_fname:
print('input file name is invalid.: {0}'.format(input_fname))
print('input file name must include \'wakati\'')
sys.exit(1)
main(input_fname)
"Stoppwortentfernung" ist der Vorgang zum Entfernen von Stoppwörtern. (Zu viel wie es ist ...)
Was ist ein "** Stoppwort **"?
Nach dem goo Landessprachenwörterbuch
Wörter, die bei Volltextsuchen so häufig vorkommen, dass sie selbst von der Suche ausgeschlossen werden. Bezieht sich auf "ha", "no", "desu" auf Japanisch und a, the, auf Englisch. Stoppwörter.
Aufgaben zur Verarbeitung natürlicher Sprache haben oft den Zweck, "den Kontext eines Satzes zu verstehen". Stoppwörter sind für diesen Zweck nicht erforderlich und sollten entfernt werden.
Es gibt zwei Hauptpunkte. Dieses Mal werden wir 1 verwenden.
Verwenden Sie für Wörterbuchdaten hier.
Es gibt mehrere Gründe für die Wahl von Methode 1.
Entfernt die Wörter, die in den im vorherigen Abschnitt eingeführten Wörterbuchdaten registriert sind. Außerdem wurden die folgenden Zeichen entfernt. Es ist ein Wort, das ich beim Stimmen verschiedener Dinge für nervig hielt.
stopword_removal.py
import pandas as pd
import urllib.request
from pathlib import Path
from tqdm import tqdm
import argparse
from pathlib import Path
import sys
def maybe_download(path: str):
stopword_def_page_url = 'http://svn.sourceforge.jp/svnroot/slothlib/CSharp/Version1/SlothLib/NLP/Filter/StopWord/word/Japanese.txt'
p = Path(path)
if p.exists():
print('File already exists.')
else:
print('downloading stop words definition ...')
# Download the file from `url` and save it locally under `file_name`:
urllib.request.urlretrieve(stopword_def_page_url, path)
#Stoppwort hinzugefügt
sw_added_list = [
'-',
'- -',
'w',
'W',
'm',
'Lol'
]
sw_added_str = '\n'.join(sw_added_list)
with open(path, 'a') as f:
print(sw_added_str, file=f)
def load_sw_definition(path: str) -> list:
with open(path, 'r', encoding='utf-8') as f:
lines = f.read()
line_list = lines.split('\n')
line_list = [x for x in line_list if x != '']
return line_list
def remove_sw_from_text(wktstr: str, stopwords: list) -> str:
words_list = wktstr.split(' ')
words_list_swrm = [x for x in words_list if x not in stopwords]
swremoved_str = ' '.join(words_list_swrm)
return swremoved_str
def remove_sw_from_msgs(wktmsg_ser: pd.Series, stopwords: list) -> pd.Series:
swremved_msg_list = []
for wktstr in tqdm(wktmsg_ser, desc='remove stopwords...'):
removed_str = remove_sw_from_text(str(wktstr), stopwords)
swremved_msg_list.append(removed_str)
swremved_msg_ser = pd.Series(swremved_msg_list)
return swremved_msg_ser
def main(input_fname: str):
input_root = '../../data/030_processed'
output_root = input_root
# 1. load stop words
sw_def_fpath = 'stopwords.txt'
maybe_download(sw_def_fpath)
stopwords = load_sw_definition(sw_def_fpath)
# 2. load messages
msgs_fpath = input_root + '/' + input_fname
df_msgs = pd.read_csv(msgs_fpath)
# 3. remove stop words
ser_msg = df_msgs.wakati_msg
df_msgs.wakati_msg = remove_sw_from_msgs(ser_msg, stopwords)
# 4. save it
pin = Path(msgs_fpath)
msgs_ofpath = output_root + '/' + pin.stem + '_rmsw.csv'
df_msgs.to_csv(msgs_ofpath, index=False)
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("input_fname", help="set input file name", type=str)
args = parser.parse_args()
input_fname = args.input_fname
# input file must been cleaned
if 'norm' not in input_fname:
print('input file name is invalid.: {0}'.format(input_fname))
print('input file name must include \'norm\'')
sys.exit(1)
main(input_fname)
Es gibt viele großartige Kommentarartikel. Ich habe auf diesen Artikel verwiesen. TF-IDF | Qiita
Hier werde ich grob erklären.
tf-idf ist das Produkt von tf und idf. Mit anderen Worten ** Großes tf-idf ** = ** Erscheint häufig in einem Dokument ** & ** Nicht oft in anderen Dokumenten ** = Wichtig für das Verständnis des ** Kontextes des Dokuments **
Der Zweck dieser Zeit ist es, die Merkmale von Bemerkungen für einen bestimmten Zeitraum (1 Woche) zu sehen. Daher dachte ich, dass es möglich sein sollte zu verstehen, ** welche Eigenschaften die Bemerkungen eines bestimmten Zeitraums (1 Woche) für alle bisherigen Beiträge haben **.
Deshalb,
Ich habe tf-idf als berechnet.
Schreiben Sie den Prozessablauf einfach
important_word_extraction.py
import pandas as pd
import json
from datetime import datetime, date, timedelta, timezone
from pathlib import Path
from sklearn.feature_extraction.text import TfidfVectorizer
JST = timezone(timedelta(hours=+9), 'JST')
#Gruppieren von Nachrichten nach einem bestimmten Zeitraum
def group_msgs_by_term(df_msgs: pd.DataFrame, term: str) -> dict:
# set term
term_days = 8
if term == 'lm':
term_days = 31
print('group messages every {0} days'.format(term_days))
# analyze timestamp
now_in_sec = (datetime.now(JST) - datetime.fromtimestamp(0, JST)).total_seconds()
interval_days = timedelta(days=term_days)
interval_seconds = interval_days.total_seconds()
oldest_timestamp = df_msgs.min().timestamp
oldest_ts_in_sec = (datetime.fromtimestamp(oldest_timestamp, JST) - datetime.fromtimestamp(0, JST)).total_seconds()
loop_num = (abs(now_in_sec - oldest_ts_in_sec) / interval_seconds) + 1
# extract by term
dict_msgs_by_term = {}
df_tmp = df_msgs
now_tmp = now_in_sec
for i in range(int(loop_num)):
# make current term string
cur_term_s = 'term_ago_{0}'.format(str(i).zfill(3))
print(cur_term_s)
# current messages
df_msgs_cur = df_tmp.query('@now_tmp - timestamp < @interval_seconds')
df_msgs_other = df_tmp.query('@now_tmp - timestamp >= @interval_seconds')
# messages does not exist. break.
if df_msgs_cur.shape[0] == 0:
break
# add current messages to dict
dict_msgs_by_term[cur_term_s] = ' '.join(df_msgs_cur.wakati_msg.dropna().values.tolist())
# update temp value for next loop
now_tmp = now_tmp - interval_seconds
df_tmp = df_msgs_other
return dict_msgs_by_term
# tf-Extrahieren Sie wichtige Wörter und geben Sie sie als Wörterbuch zurück, während Sie sich auf die IDF-Punktzahl beziehen
def extract_important_word_by_key(feature_names: list, bow_df: pd.DataFrame, uids: list) -> dict:
# >Schauen Sie sich jede Zeile an und extrahieren Sie wichtige Wörter(tfidf Top X Wörter)
dict_important_words_by_user = {}
for uid, (i, scores) in zip(uids, bow_df.iterrows()):
#Erstellen Sie eine Tabelle mit Wörtern und tfidf-Ergebnissen für den Benutzer
words_score_tbl = pd.DataFrame()
words_score_tbl['scores'] = scores
words_score_tbl['words'] = feature_names
#Sortieren Sie in absteigender Reihenfolge nach tfidf score
words_score_tbl = words_score_tbl.sort_values('scores', ascending=False)
words_score_tbl = words_score_tbl.reset_index()
# extract : tf-idf score > 0.001
important_words = words_score_tbl.query('scores > 0.001')
#Erstellen eines Wörterbuchs für den Benutzer'uid0': {'w0': 0.9, 'w1': 0.87}
d = {}
for i, row in important_words.iterrows():
d[row.words] = row.scores
#Nur zur Tabelle hinzufügen, wenn das Wörterbuch des Benutzers mindestens ein Wort enthält
if len(d.keys()) > 0:
dict_important_words_by_user[uid] = d
return dict_important_words_by_user
#Extrahieren Sie wichtige Wörter in der angegebenen Periodeneinheit
def extraction_by_term(input_root: str, output_root: str, term: str) -> dict:
# ---------------------------------------------
# 1. load messages (processed)
# ---------------------------------------------
print('load msgs (all of history and last term) ...')
msg_fpath = input_root + '/' + 'messages_cleaned_wakati_norm_rmsw.csv'
df_msgs_all = pd.read_csv(msg_fpath)
# ---------------------------------------------
# 2. group messages by term
# ---------------------------------------------
print('group messages by term and save it.')
msgs_grouped_by_term = group_msgs_by_term(df_msgs_all, term)
msg_grouped_fpath = input_root + '/' + 'messages_grouped_by_term.json'
with open(msg_grouped_fpath, 'w', encoding='utf-8') as f:
json.dump(msgs_grouped_by_term, f, ensure_ascii=False, indent=4)
# ---------------------------------------------
# 3.Tf für alle Dokumente-IDF-Berechnung
# ---------------------------------------------
print('tfidf vectorizing ...')
# >Wörter in allen Dokumenten sind Spalten und die Anzahl der Dokumente (=Es wird eine Matrix erstellt, in der Benutzer) die Zeile ist. Tf für jedes Element-Es gibt einen IDF-Wert
tfidf_vectorizer = TfidfVectorizer(token_pattern=u'(?u)\\b\\w+\\b')
bow_vec = tfidf_vectorizer.fit_transform(msgs_grouped_by_term.values())
bow_array = bow_vec.toarray()
bow_df = pd.DataFrame(bow_array,
index=msgs_grouped_by_term.keys(),
columns=tfidf_vectorizer.get_feature_names())
# ---------------------------------------------
# 5. tf-Extrahieren Sie wichtige Wörter basierend auf idf
# ---------------------------------------------
print('extract important words ...')
dict_word_score_by_term = extract_important_word_by_key(
tfidf_vectorizer.get_feature_names(),
bow_df, msgs_grouped_by_term.keys())
return dict_word_score_by_term
Wörter mit einer hohen Punktzahl sind groß und Wörter mit einer niedrigen Punktzahl sind klein. Verschiedene Werte wie "Auftrittshäufigkeit" und "Wichtigkeit" können für die Partitur frei eingestellt werden.
Offizielles Repository: amueller / word_cloud: octocat:
Dieses Mal werde ich dies verwenden. Was ist hausgemachtes abgerundetes M +
Im vorherigen Kapitel "8. Vorverarbeitung: Extrahieren wichtiger Wörter (tf-idf)" wurde die folgende JSON-Datei ausgegeben.
important_word_tfidf_by_term.json
{
"term_ago_000": {
"Daten": 0.890021,
"Spiel": 0.780122,
"Artikel": 0.720025,
:
},
"term_ago_001": {
"Übersetzung": 0.680021,
"Daten": 0.620122,
"deepl": 0.580025,
:
},
:
}
Laden Sie dies und erstellen Sie ein Wordcloud-Bild. Verwenden Sie die Methode "WordCloud.generate_from_frequancies ()".
wordcloud_from_score.py
from wordcloud import WordCloud
import matplotlib.pyplot as plt
import json
from pathlib import Path
from sklearn.feature_extraction.text import TfidfVectorizer
import pandas as pd
from tqdm import tqdm
import sys
import argparse
def main(input_fname: str):
input_root = '../../data/031_features'
output_root = './wordcloud_by_user' if 'by_user' in input_fname else './wordcloud_by_term'
p = Path(output_root)
if p.exists() is False:
p.mkdir()
# -------------------------------------
# 1. load tf-idf score dictionary
# -------------------------------------
d_word_score_by_user = {}
tfidf_fpath = input_root + '/' + input_fname
with open(tfidf_fpath, 'r', encoding='utf-8') as f:
d_word_score_by_user = json.load(f)
# -------------------------------------
# 2. gen word cloud from score
# -------------------------------------
fontpath = './rounded-l-mplus-1c-regular.ttf'
for uname, d_word_score in tqdm(d_word_score_by_user.items(), desc='word cloud ...'):
# img file name is user.png
uname = str(uname).replace('/', '-')
out_img_fpath = output_root + '/' + uname + '.png'
# gen
wc = WordCloud(
background_color='white',
font_path=fontpath,
width=900, height=600,
collocations=False
)
wc.generate_from_frequencies(d_word_score)
wc.to_file(out_img_fpath)
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("input_fname", help="set input file name", type=str)
args = parser.parse_args()
input_fname = args.input_fname
main(input_fname)
Andere Referenzmaterialien (große Menge) sind in hier: octocat: zusammengefasst.
Dieses Mal verwenden wir Daten aus der Slack-Community namens Data Learning Guild. Die Data Learning Guild ist eine Online-Community von Datenanalyse-Mitarbeitern. Wenn Sie interessiert sind, überprüfen Sie bitte hier.
Offizielle Homepage der Data Learning Guild
Adventskalender 2019 der Data Learning Guild
Recommended Posts