Standardmäßig ist der Prompt ausgewählt, der zuerst die Quelle prüft. Sie können zu einem direkten Befehl wechseln oder eine lokale Kopie herunterladen.
Quelldateien prüfen
Lesen Sie SKILL.md und alle von SkillsMP angezeigten Begleitdateien, bevor Sie sich für eine Installation entscheiden.
Mit Codex oder Claude installieren Kopieren Sie diesen Prompt, fügen Sie ihn in Codex, Claude oder einen anderen Assistant ein und lassen Sie die Skill-Seite prüfen und installieren.
Ein direkter Befehl überspringt den Prüf-Prompt. Prüfen Sie die Quelle, bevor Sie ihn ausführen.
import numpy as np
import pandas as pd
from sklearn.feature_extraction.text import TfidfVectorizer, CountVectorizer
sklearn.decomposition LatentDirichletAllocation, NMF
matplotlib.pyplot plt
()
from
import
import
as
print
"Text mining environment ready"
Core Workflow
Step 1: Topic Modeling with LDA and NMF
import numpy as np
import pandas as pd
from sklearn.feature_extraction.text import CountVectorizer, TfidfVectorizer
from sklearn.decomposition import LatentDirichletAllocation, NMF
import matplotlib.pyplot as plt
import re
# -----------------------------------------------------------------# Simulate a corpus of 300 scientific abstracts across 5 topics# -----------------------------------------------------------------
np.random.seed(42)
topic_vocab = {
"Machine Learning": [
"neural network", "deep learning", "gradient descent", "training",
"convolutional", "transformer", "attention mechanism", "overfitting",
"regularization", "classification", "accuracy", "loss function",
"backpropagation", "batch normalization", "dropout"
],
"Climate Science": [
"greenhouse gas", "carbon dioxide", "temperature anomaly", "precipitation",
"sea level rise", "ocean acidification", "feedback mechanism", "forcing",
"radiative", "atmosphere", "climate model", "warming", "emission",
"renewable energy", "carbon sequestration"
],
"Genomics": [
"gene expression", "RNA sequencing", "genome", "mutation", "protein",
"transcription factor", "epigenetics", "methylation", "chromosomal",
"single nucleotide polymorphism", "CRISPR", "variant", "allele",
"gene regulatory network", "pathway analysis"
],
"Urban Planning": [
"land use", "zoning regulation", "transit oriented development",
"density", "walkability", "urban heat island", "infrastructure",
"mixed use", "smart city", "mobility", "accessibility", "gentrification",
"housing policy", "neighborhood", "transportation network"
],
"Quantum Physics": [
"quantum entanglement", "superposition", "wave function", "Hamiltonian",
"decoherence", "qubit", "quantum gate", "Hilbert space", "operator",
"measurement", "quantum computing", "interference", "photon",
"Schrödinger equation", "eigenvalue"
],
}
topic_names = list(topic_vocab.keys())
defgenerate_abstract(topic, n_sentences=4):
"""Generate a synthetic abstract for a given topic."""
words = topic_vocab[topic]
sentences = []
for _ inrange(n_sentences):
n_words = np.random.randint(3, 7)
chosen = np.random.choice(words, n_words, replace=True)
# Add generic scientific text
fillers = ["we present", "this study investigates", "results show",
"we demonstrate", "our approach", "analysis reveals"]
sentence = np.random.choice(fillers) + " " + " and ".join(chosen)
sentences.append(sentence)
return". ".join(sentences) + "."# Generate corpus with mixed topics
abstracts = []
doc_topics = []
for _ inrange(300):
# Allow some mixing
primary_topic = np.random.choice(topic_names)
text = generate_abstract(primary_topic)
# 20% chance of adding secondary topic contentif np.random.random() < 0.2:
secondary = np.random.choice([t for t in topic_names if t != primary_topic])
text += " " + generate_abstract(secondary, n_sentences=1)
abstracts.append(text)
doc_topics.append(primary_topic)
df_corpus = pd.DataFrame({"abstract": abstracts, "true_topic": doc_topics})
# -----------------------------------------------------------------# Preprocessing# -----------------------------------------------------------------defpreprocess_text(text):
"""Basic text preprocessing: lowercase, remove special chars."""
text = text.lower()
text = re.sub(r"[^a-z\s]", " ", text)
text = re.sub(r"\s+", " ", text).strip()
return text
df_corpus["clean_text"] = df_corpus["abstract"].apply(preprocess_text)
# -----------------------------------------------------------------# TF-IDF + NMF Topic Modeling# -----------------------------------------------------------------
n_topics = 5
n_top_words = 10
tfidf = TfidfVectorizer(max_df=0.95, min_df=2, max_features=500,
stop_words="english")
X_tfidf = tfidf.fit_transform(df_corpus["clean_text"])
feature_names = tfidf.get_feature_names_out()
nmf = NMF(n_components=n_topics, random_state=42, max_iter=400)
W_nmf = nmf.fit_transform(X_tfidf) # document-topic matrix (n_docs, n_topics)
H_nmf = nmf.components_ # topic-word matrix (n_topics, n_vocab)print("=== NMF Top Words per Topic ===")
for topic_idx inrange(n_topics):
top_words_idx = H_nmf[topic_idx].argsort()[-n_top_words:][::-1]
top_words = [feature_names[i] for i in top_words_idx]
print(f"Topic {topic_idx + 1}: {', '.join(top_words)}")
# -----------------------------------------------------------------# LDA Topic Modeling# -----------------------------------------------------------------
tf_vec = CountVectorizer(max_df=0.95, min_df=2, max_features=500,
stop_words="english")
X_tf = tf_vec.fit_transform(df_corpus["clean_text"])
tf_features = tf_vec.get_feature_names_out()
lda = LatentDirichletAllocation(n_components=n_topics, random_state=42,
learning_method="online", max_iter=50)
W_lda = lda.fit_transform(X_tf) # document-topic matrixprint("\n=== LDA Top Words per Topic ===")
for topic_idx inrange(n_topics):
top_idx = lda.components_[topic_idx].argsort()[-n_top_words:][::-1]
top_words = [tf_features[i] for i in top_idx]
print(f"Topic {topic_idx + 1}: {', '.join(top_words)}")
# -----------------------------------------------------------------# Assign dominant topic to each document# -----------------------------------------------------------------
df_corpus["nmf_topic"] = W_nmf.argmax(axis=1)
df_corpus["lda_topic"] = W_lda.argmax(axis=1)
# Topic distributionprint("\nNMF Topic Distribution:")
print(df_corpus["nmf_topic"].value_counts().sort_index())
# -----------------------------------------------------------------# Visualization# -----------------------------------------------------------------
fig, axes = plt.subplots(1, 2, figsize=(14, 5))
# Topic word bars (NMF)for topic_idx inrange(n_topics):
top_n = 8
top_idx = H_nmf[topic_idx].argsort()[-top_n:][::-1]
words = [feature_names[i] for i in top_idx]
scores = H_nmf[topic_idx][top_idx]
axes[0].barh([f"T{topic_idx+1}: {w[:15]}"for w in words],
scores, alpha=0.6,
label=f"Topic {topic_idx+1}")
axes[0].set_title("NMF Topic-Word Loadings")
axes[0].set_xlabel("Weight")
# Document-topic heatmap (sample of 30 docs)
sample_idx = np.random.choice(len(df_corpus), 30, replace=False)
im = axes[1].imshow(W_nmf[sample_idx], cmap="YlOrRd", aspect="auto")
axes[1].set_xlabel("Topic"); axes[1].set_ylabel("Document (sample)")
axes[1].set_title("Document-Topic Matrix (NMF)")
axes[1].set_xticks(range(n_topics))
axes[1].set_xticklabels([f"T{i+1}"for i inrange(n_topics)])
plt.colorbar(im, ax=axes[1])
plt.tight_layout()
plt.savefig("topic_modeling.png", dpi=150, bbox_inches="tight")
plt.close()
print("\nFigure saved: topic_modeling.png")
Step 2: Keyword Extraction and Trend Analysis
import numpy as np
import pandas as pd
from sklearn.feature_extraction.text import TfidfVectorizer
import matplotlib.pyplot as plt
from collections import Counter
import re
# -----------------------------------------------------------------# Add years to corpus for trend analysis# -----------------------------------------------------------------
years = np.random.randint(2010, 2024, len(df_corpus))
df_corpus["year"] = years
# -----------------------------------------------------------------# RAKE-inspired keyword extraction# -----------------------------------------------------------------defrake_keywords(text, stopwords=None, min_chars=4, max_words=4):
"""Simple RAKE keyword extraction.
Args:
text: input string
stopwords: set of stop words
min_chars: minimum keyword character length
max_words: max words in a keyphrase
Returns:
list of (score, keyphrase) tuples
"""if stopwords isNone:
stopwords = {"the", "a", "an", "and", "or", "in", "on", "at",
"to", "of", "for", "we", "our", "this", "these", "is"}
# Split on stop words and punctuation
phrase_list = re.split(r"\b(?:" + "|".join(stopwords) + r")\b|[,\.;:()\[\]]",
text.lower())
candidate_phrases = [p.strip() for p in phrase_list
iflen(p.strip()) >= min_chars]
candidate_phrases = [p for p in candidate_phrases
if1 <= len(p.split()) <= max_words]
# Word frequency and degree
word_freq = Counter()
word_degree = Counter()
for phrase in candidate_phrases:
words = phrase.split()
for w in words:
word_freq[w] += 1
word_degree[w] += len(words)
# Score phrases
scored = []
for phrase in candidate_phrases:
words = phrase.split()
score = sum(word_degree[w] / max(word_freq[w], 1) for w in words)
scored.append((score, phrase))
returnsorted(scored, reverse=True)[:10]
# Extract keywords for a sample abstract
sample_text = df_corpus["abstract"].iloc[0]
print("=== RAKE Keywords from Sample Abstract ===")
print(f"Abstract: {sample_text[:200]}...")
for score, kw in rake_keywords(sample_text)[:5]:
print(f" '{kw}' (score={score:.2f})")
# -----------------------------------------------------------------# TF-IDF keyword extraction over the full corpus# -----------------------------------------------------------------
tfidf_kw = TfidfVectorizer(max_df=0.8, min_df=3, ngram_range=(1, 3),
max_features=1000, stop_words="english")
X_kw = tfidf_kw.fit_transform(df_corpus["clean_text"])
kw_names = tfidf_kw.get_feature_names_out()
# Top keywords by mean TF-IDF score
mean_tfidf = X_kw.mean(axis=0).A1
top_kw_idx = mean_tfidf.argsort()[-20:][::-1]
top_keywords = [(kw_names[i], mean_tfidf[i]) for i in top_kw_idx]
print("\n=== Top 20 Keywords (TF-IDF) ===")
for kw, score in top_keywords:
print(f" {kw}: {score:.4f}")
# -----------------------------------------------------------------# Temporal keyword trend (annual frequency)# -----------------------------------------------------------------
all_keywords = [kw for kw, _ in top_keywords[:8]]
trend_data = []
for yr inrange(2010, 2024):
yr_docs = df_corpus[df_corpus["year"] == yr]["clean_text"]
iflen(yr_docs) == 0:
continue
yr_text = " ".join(yr_docs)
yr_counts = {kw: yr_text.count(kw) / max(len(yr_docs), 1)
for kw in all_keywords}
yr_counts["year"] = yr
trend_data.append(yr_counts)
trend_df = pd.DataFrame(trend_data).set_index("year")
# -----------------------------------------------------------------# Visualization# -----------------------------------------------------------------
fig, axes = plt.subplots(1, 2, figsize=(14, 5))
# Top keywords bar chart
kw_labels, kw_scores = zip(*top_keywords)
axes[0].barh(kw_labels[::-1], kw_scores[::-1], color="steelblue", edgecolor="black")
axes[0].set_xlabel("Mean TF-IDF Score")
axes[0].set_title("Top Keywords by TF-IDF")
# Temporal trends for top keywordsfor kw in all_keywords[:5]:
if kw in trend_df.columns:
axes[1].plot(trend_df.index, trend_df[kw], marker="o", ms=3, label=kw)
axes[1].set_xlabel("Year"); axes[1].set_ylabel("Avg. Frequency per Document")
axes[1].set_title("Keyword Temporal Trends")
axes[1].legend(fontsize=7)
plt.tight_layout()
plt.savefig("keyword_trends.png", dpi=150, bbox_inches="tight")
plt.close()
print("\nFigure saved: keyword_trends.png")
Step 3: Scientific NER and Claim Extraction
import re
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from collections import Counter
# -----------------------------------------------------------------# Rule-based scientific NER (pattern matching approach)# For production use: spaCy + SciBERT or SciSpacy# -----------------------------------------------------------------
NER_PATTERNS = {
"METHOD": [
r"\b(random forest|neural network|LSTM|transformer|SVM|k-means|"r"linear regression|logistic regression|BERT|XGBoost|gradient boosting|"r"Monte Carlo|Bayesian inference|MCMC|principal component analysis|PCA)\b",
],
"METRIC": [
r"\b(accuracy|F1[- ]score|precision|recall|AUC|RMSE|MAE|R[²²]|"r"p[- ]value|confidence interval|statistical significance|"r"mean absolute error|root mean square)\b",
],
"DATASET": [
r"\b(ImageNet|MNIST|CIFAR|Wikipedia|PubMed|MEDLINE|arXiv|"r"MIMIC|UK Biobank|NHANES|CelebA|Penn Treebank|SQuAD)\b",
],
"CLAIM_VERB": [
r"\b(we show|we demonstrate|we find|we propose|our results|"r"results indicate|we report|our study|we observe|analysis shows)\b",
],
}
defscientific_ner(text, patterns=NER_PATTERNS):
"""Extract named entities from scientific text using regex patterns.
Args:
text: input string
patterns: dict of {entity_type: [regex_patterns]}
Returns:
dict of {entity_type: [mentions]}
"""
entities = {etype: [] for etype in patterns}
text_lower = text.lower()
for etype, pattern_list in patterns.items():
for pattern in pattern_list:
matches = re.findall(pattern, text_lower, re.IGNORECASE)
entities[etype].extend([m.strip() for m in matches])
# Deduplicatefor etype in entities:
entities[etype] = list(set(entities[etype]))
return entities
defextract_claims(text):
"""Extract sentences that contain scientific claims.
Args:
text: abstract or paper section
Returns:
list of claim sentences
"""# Split into sentences
sentences = re.split(r"[.!?]", text)
claim_indicators = [
r"\b(we show|we demonstrate|we find|we propose|we present|"r"our results|results indicate|results suggest|we observe|"r"analysis shows|our model|our approach|our method)\b"
]
claims = []
for sent in sentences:
sent = sent.strip()
iflen(sent) < 20:
continuefor indicator in claim_indicators:
if re.search(indicator, sent, re.IGNORECASE):
claims.append(sent)
breakreturn claims
# -----------------------------------------------------------------# Apply NER and claim extraction to corpus# -----------------------------------------------------------------
all_entities = {etype: [] for etype in NER_PATTERNS}
all_claims = []
for text in df_corpus["abstract"].head(100):
entities = scientific_ner(text)
for etype, ents in entities.items():
all_entities[etype].extend(ents)
claims = extract_claims(text)
all_claims.extend(claims)
# Entity frequency analysisprint("=== Scientific Entity Frequency (top 10) ===")
for etype, ents in all_entities.items():
counter = Counter([e.lower() for e in ents])
print(f"\n{etype}:")
for ent, count in counter.most_common(5):
print(f" '{ent}': {count}")
print(f"\nExtracted {len(all_claims)} claim sentences from 100 abstracts")
print("Sample claims:")
for claim in all_claims[:3]:
print(f" - {claim[:100]}...")
# -----------------------------------------------------------------# Visualization: Entity frequency heatmap# -----------------------------------------------------------------
fig, axes = plt.subplots(2, 2, figsize=(12, 8))
etype_list = list(NER_PATTERNS.keys())
for ax, etype inzip(axes.flatten(), etype_list):
counter = Counter([e.lower() for e in all_entities[etype]])
if counter:
labels, counts = zip(*counter.most_common(8))
ax.barh(list(labels)[::-1], list(counts)[::-1],
color="steelblue", edgecolor="black")
ax.set_title(f"{etype} Mentions")
ax.set_xlabel("Count")
else:
ax.text(0.5, 0.5, f"No {etype} found", ha="center", va="center",
transform=ax.transAxes)
plt.tight_layout()
plt.savefig("scientific_ner.png", dpi=150, bbox_inches="tight")
plt.close()
print("\nFigure saved: scientific_ner.png")
Advanced Usage
BERTopic-Style Contextual Topic Modeling
import numpy as np
import pandas as pd
from sklearn.decomposition import PCA
from sklearn.cluster import KMeans
from sklearn.feature_extraction.text import TfidfVectorizer
defbertopic_simplified(texts, n_topics=5, embedding_dim=50):
"""Simplified BERTopic pipeline without transformer models.
Uses TF-IDF + PCA + K-Means as a lightweight substitute for
BERT embeddings + UMAP + HDBSCAN.
Args:
texts: list of text strings
n_topics: number of topics
embedding_dim: PCA dimensions for pre-clustering
Returns:
topic assignments, topic keywords
"""# Step 1: TF-IDF document embeddings
vectorizer = TfidfVectorizer(max_features=1000, stop_words="english")
X = vectorizer.fit_transform(texts).toarray()
# Step 2: Dimensionality reduction (PCA as UMAP substitute)
pca = PCA(n_components=min(embedding_dim, X.shape[1] - 1), random_state=42)
X_reduced = pca.fit_transform(X)
# Step 3: K-Means clustering (as HDBSCAN substitute)
kmeans = KMeans(n_clusters=n_topics, random_state=42, n_init=10)
labels = kmeans.fit_predict(X_reduced)
# Step 4: Class-based TF-IDF for topic words (c-TF-IDF)
feature_names = vectorizer.get_feature_names_out()
topic_words = {}
for t inrange(n_topics):
doc_mask = labels == t
if doc_mask.sum() == 0:
continue# Mean TF-IDF in cluster
cluster_tfidf = X[doc_mask].mean(axis=0)
top_idx = cluster_tfidf.argsort()[-10:][::-1]
topic_words[t] = [feature_names[i] for i in top_idx]
return labels, topic_words
labels_bt, topic_words_bt = bertopic_simplified(
df_corpus["clean_text"].tolist(), n_topics=5)
print("=== BERTopic-Simplified Topics ===")
for t, words in topic_words_bt.items():
print(f"Topic {t}: {', '.join(words[:7])}")
Topic Coherence Evaluation
import numpy as np
from collections import defaultdict
from itertools import combinations
defcompute_npmi_coherence(top_words_per_topic, corpus_texts, window=10):
"""Compute NPMI-based coherence for each topic.
Args:
top_words_per_topic: list of lists, each = top N words for a topic
corpus_texts: list of preprocessed text strings
window: co-occurrence window size (in words)
Returns:
list of per-topic NPMI coherence scores
"""# Build word co-occurrence counts
word_count = defaultdict(int)
pair_count = defaultdict(int)
total_windows = 0for text in corpus_texts:
words = text.split()
for i, w inenumerate(words):
word_count[w] += 1
window_words = words[max(0, i-window):i+window+1]
for w2 in window_words:
if w2 != w:
pair_count[tuple(sorted([w, w2]))] += 1
total_windows += max(1, len(words))
# NPMI for word pairsdefnpmi(w1, w2, N):
c1 = word_count.get(w1, 0) + 1
c2 = word_count.get(w2, 0) + 1
c12 = pair_count.get(tuple(sorted([w1, w2])), 0) + 1
pmi = np.log(c12 * N / (c1 * c2 + 1e-10))
npmi_val = pmi / max(-np.log(c12 / N + 1e-10), 1e-10)
return npmi_val
coherence_scores = []
for topic_words in top_words_per_topic:
N = max(total_windows, 1)
pairs = list(combinations(topic_words[:10], 2))
ifnot pairs:
coherence_scores.append(0.0)
continue
pair_npmis = [npmi(w1, w2, N) for w1, w2 in pairs]
coherence_scores.append(float(np.mean(pair_npmis)))
return coherence_scores
# Get top words from NMF model (already fit above)
topic_words_nmf = []
for topic_idx inrange(n_topics):
top_idx = H_nmf[topic_idx].argsort()[-10:][::-1]
topic_words_nmf.append([feature_names[i] for i in top_idx])
coh_scores = compute_npmi_coherence(topic_words_nmf,
df_corpus["clean_text"].tolist())
print("\n=== NMF Topic Coherence (NPMI) ===")
for i, score inenumerate(coh_scores):
print(f"Topic {i+1}: {score:.4f}")
print(f"Mean coherence: {np.mean(coh_scores):.4f}")
Troubleshooting
Problem
Cause
Fix
LDA gives incoherent topics
Too few documents or too many topics
Reduce n_topics; increase min_df in vectorizer
NMF topics overlap significantly
K too large or corpus not diverse enough
Decrease K; add orthogonality constraint
TF-IDF keywords are stopwords
stop_words not configured
Use stop_words="english" or custom stopword list
RAKE extracts long nonsense phrases
Aggressive splitting
Increase min_chars; add more stopwords
NER misses multi-word entities
Regex too strict
Add more patterns; consider spaCy + SciSpacy
Coherence score negative
Sparse co-occurrences
Increase corpus size or window size
External Resources
Blei, D. M., et al. (2003). Latent Dirichlet Allocation. JMLR, 3, 993-1022.
Lee, D. D., & Seung, H. S. (1999). Learning the parts of objects by NMF. Nature.
Grootendorst, M. (2022). BERTopic: Neural topic modeling with class-based TF-IDF. arXiv:2203.05794.