Automatikus témamodellezés Pythonnal
A témamodellezés segítségével megtalálhatjuk a rejtett mintákat és témákat a dokumentumokban. Ebben a blogbejegyzésben bemutatok egy egyszerű Python programot, amely lehetővé teszi a témamodellezést HTML forrásokon, feltérképezhetjük a kulcsszavakat és a témákat a weboldalakon, ezáltal könnyebben értelmezhetjük az online tartalmakat.
A felhasználó megadhat egy listát az URL-ekről és az azokhoz kapcsolódó címkékről. A programban a BeautifulSoupot használjuk a weboldalak letöltésére, majd preprocesszáljuk a szöveget a stop szavak eltávolításával és tokenizálással. A témák azonosítására a Gensim modult választottam. Az LDA (Latent Dirichlet Allocation) algoritmust alkalmazzuk a témamodellezésre.
Hozzunk létre egy projektkönyvtárat:
mkdir topic
cd topic
Majd a szükséges virtuális környezetet:
python3 -m venv .venv
source .venv/bin/activate
A következő könyvtárakat kell telepíteni a program használatához:
pip install beautifulsoup4
pip install gensim
pip install nltk
pip install requests
Hozzunk létre egy topic.py fájlt a projekt mappájában. A teljes példakód:
#!/usr/bin/env python3
import string
import argparse
import requests
from bs4 import BeautifulSoup
import gensim
from gensim import corpora
from gensim.models import LdaModel
from nltk.tokenize import word_tokenize
from nltk.corpus import stopwords
import nltk
nltk.download("stopwords")
nltk.download('punkt')
# Magyar stopwords lista beolvasása
with open('magyar_stopwords.txt', 'r', encoding='utf-8') as stopwords_file:
magyar_stopwords = stopwords_file.read().splitlines()
def download_and_preprocess(url):
# HTML tartalom letöltése
response = requests.get(url)
html_content = response.text
# HTML tartalom feldolgozása a BeautifulSoup segítségével
soup = BeautifulSoup(html_content, "html.parser")
# Hasznos szövegrész kinyerése (pl. címek és paragrafusok)
useful_text = ""
for element in soup.find_all(["h1", "h2", "h3", "p"]):
useful_text += element.get_text() + " "
return useful_text
def preprocess_text(text):
# Tokenizálás
tokens = word_tokenize(text.lower())
# Stop szavak és szóközök eltávolítása
tokens = [word for word in tokens if word not in magyar_stopwords and word not in string.punctuation]
return tokens
def perform_topic_modeling(text_tokens, num_topics=5):
dictionary = corpora.Dictionary([text_tokens])
corpus = [dictionary.doc2bow(text_tokens)]
lda_model = LdaModel(corpus, num_topics=num_topics, id2word=dictionary)
return lda_model
def main():
parser = argparse.ArgumentParser(description='Témamodellezés HTML tartalmak alapján')
parser.add_argument('file', type=argparse.FileType('r'), help='A txt fájl elérési útja')
parser.add_argument('--topics', type=int, default=5, help='Témák száma')
args = parser.parse_args()
url_topics = {} # URL és hozzájuk rendelt témák tárolása
for line in args.file:
parts = line.strip().split() # URL és címke elválasztása
url = parts[0]
label = parts[1] if len(parts) > 1 else url # Címke, vagy az URL, ha nincs megadva
useful_text = download_and_preprocess(url)
text_tokens = preprocess_text(useful_text)
lda_model = perform_topic_modeling(text_tokens, args.topics)
topics = lda_model.show_topics()
# Témák az URL alapján
url_topics[url] = []
for i, topic in enumerate(topics):
url_topics[url].append(f'Téma {i + 1}: {topic}')
# Összefoglaló az összes témáról a teljes corpusban
print('Témák a teljes corpusban:')
for url, topics in url_topics.items():
print(f'{url} témái:')
for topic in topics:
print(topic)
print('\n')
if __name__ == '__main__':
main()
Szükség lesz még két fájlra: a magyar_stopwords.txt és az url_labels.txt. A fájlok hozzáadása, melyeket szintén a projekt gyökérkönyvtárában kell létrehozni:
touch magyar_stopwords.txt
touch url_labels.txt
Példa az url_labels.txt tartalmára:
# url_labels.txt
http://www.magyarorszag.hu/
http://www.magyarorszag.hu/nyugat/
Példa a magyar_stopwords.txt tartalmára:
# magyar_stopwords.txt
is
és
...
új
újra
után
utána
utolsó
A program használata:
python3 topic.py <input_file> --topics <num_topics>
Ahol <input_file> az url_labels.txt fájl elérési útvonala, és a <num_topics> a kívánt témák száma.
A kód működési elve a következő:
- Beolvassa a megadott URL-eket és az azokhoz rendelt címkéket az url_labels.txt fájlból.
- Letölti az URL-ek tartalmát és előfeldolgozza a szöveget.
- Témamodellezi az egyes URL-ek tartalmát a gensim segítségével.
- Kiírja az összes URL-hez rendelt témát.
Segítség a stopwords fájl feltöltéséhez:
Példa a program kimenetére:
python3 topic.py url_labels.txt --topics 3
[nltk_data] Downloading package stopwords to /home/zsolt/nltk_data...
[nltk_data] Package stopwords is already up-to-date!
[nltk_data] Downloading package punkt to /home/zsolt/nltk_data...
[nltk_data] Package punkt is already up-to-date!
Témák a teljes corpusban:
https://telex.hu/komplex/2023/10/15/varroda-textilipar-divatipar-kornyezetszennyezes-globalizacio-ujrahasznositas témái:
Téma 1: (0, '0.003*"magyar" + 0.003*"divatipar" + 0.003*"készült" + 0.003*"része" + 0.002*"termékek" + 0.002*"ugyanakkor" + 0.002*"fashion" + 0.002*"gyártás" + 0.002*"káros" + 0.002*"ellátási"')
Téma 2: (1, '0.003*"divatipar" + 0.002*"cég" + 0.002*"ugyanakkor" + 0.002*"ruhák" + 0.002*"magyar" + 0.002*"része" + 0.002*"gyártás" + 0.002*"ellátási" + 0.002*"óceáni" + 0.002*"természetes"')
Téma 3: (2, '0.003*"magyar" + 0.003*"készült" + 0.003*"divatipar" + 0.003*"része" + 0.002*"termékek" + 0.002*"gyártás" + 0.002*"óceáni" + 0.002*"korábban" + 0.002*"ugyanakkor" + 0.002*"fenntartható"')
https://telex.hu/kulfold/2023/10/15/lengyelorszag-valasztas-elorejelzes-kaczynski-pis-tusk-ko témái:
Téma 1: (0, '0.006*"pis" + 0.006*"lengyel" + 0.005*"lengyelország" + 0.004*"állami" + 0.004*"harmadik" + 0.004*"ellenzék" + 0.003*"varsó" + 0.003*"tusk" + 0.003*"polgári" + 0.003*"európai"')
Téma 2: (1, '0.009*"pis" + 0.007*"lengyel" + 0.004*"lengyelország" + 0.004*"ellenzék" + 0.004*"ukrán" + 0.003*"harmadik" + 0.003*"polgári" + 0.003*"varsó" + 0.003*"állami" + 0.003*"tusk"')
Téma 3: (2, '0.009*"pis" + 0.007*"lengyel" + 0.005*"ellenzék" + 0.004*"lengyelország" + 0.004*"harmadik" + 0.004*"tusk" + 0.003*"kormány" + 0.003*"ukrán" + 0.003*"európai" + 0.003*"elmúlt"')
https://transtelex.ro/eletmod/2023/10/15/buszkeseg-es-beton-szociofoto-avasi-falvak témái:
Téma 1: (0, '0.005*"avasi" + 0.004*"călinescu" + 0.004*"generáció" + 0.004*"ioana" + 0.003*"petruț" + 0.003*"avasiak" + 0.003*"beton" + 0.003*"két" + 0.003*"hagyományos" + 0.003*"külföldön"')
Téma 2: (1, '0.006*"avasi" + 0.005*"călinescu" + 0.005*"generáció" + 0.004*"ioana" + 0.004*"petruț" + 0.003*"beton" + 0.003*"avasiak" + 0.002*"két" + 0.002*"házak" + 0.002*"év"')
Téma 3: (2, '0.005*"avasi" + 0.005*"călinescu" + 0.004*"generáció" + 0.004*"avasiak" + 0.004*"hagyományos" + 0.004*"petruț" + 0.003*"beton" + 0.003*"ők" + 0.003*"ioana" + 0.003*"külföldön"')
https://telex.hu/kulfold/2023/10/15/izraeli-palesztin-konfliktus-9-nap-percrol-percre-gazai-ovezet témái:
Téma 1: (0, '0.012*"izraeli" + 0.007*"hamász" + 0.006*"gázai" + 0.006*"izrael" + 0.004*"fruzsina" + 0.004*"hadsereg" + 0.003*"előd" + 0.003*"vasárnap" + 0.003*"idf" + 0.003*"északi"')
Téma 2: (1, '0.015*"izraeli" + 0.007*"gázai" + 0.007*"hamász" + 0.006*"hadsereg" + 0.005*"idf" + 0.004*"fruzsina" + 0.004*"előd" + 0.004*"izrael" + 0.004*"vasárnap" + 0.003*"bbc"')
Téma 3: (2, '0.020*"izraeli" + 0.009*"hamász" + 0.009*"gázai" + 0.007*"izrael" + 0.007*"előd" + 0.006*"fruzsina" + 0.005*"hadsereg" + 0.005*"idf" + 0.003*"vasárnap" + 0.003*"közölte"')