Builders¶
Builders compute the adjacency matrix — the edges of the word-document graph — from the preprocessed corpus. Run a builder after TextPipeline and before GNN.
Builder (enum)¶
Selects which adjacency file GNN loads at training time. Builder is a str enum, so GNN(builder=...) also accepts the plain value (e.g. "embedding.word2vec").
| Value | Adjacency file prefix | Built by |
|---|---|---|
Builder.Tfidf |
frequency.tfidf |
Frequency(...).tfidf() |
Builder.Word2Vec |
embedding.word2vec |
Semantic(...).word2vec() |
Builder.Bert |
embedding.bert |
Semantic(...).bert() |
Builder.CosineSimilarity |
cosine.similarity |
Semantic(...).cosine_similarity() |
Builder.DependencyParsing |
dependency.parsing |
Syntactic(...).dependency_parsing() |
Builder.Liwc |
liwc |
Syntactic(...).linguistic_inquiry() |
Frequency¶
Builds a TF-IDF–weighted word-document graph. Fastest option; recommended as a starting point.
The constructors of Frequency, Semantic and Syntactic raise ValueError if dataset_name is empty or verbose is not 0, 1 or 2, and FileNotFoundError if dataset_path does not exist. Every builder method raises FileNotFoundError, with the TextPipeline command to run, if {dataset_path}/{dataset_name}.shuffled/ is missing.
class Frequency:
def __init__(self, dataset_name: str, dataset_path: str | os.PathLike[str], verbose: int = 1) -> None
tfidf()¶
Computes word-word co-occurrence weights via PMI in a sliding window, and word-document weights via TF-IDF. Writes ind.frequency.tfidf.{dataset_name}.adj to {dataset_path}/{dataset_name}.adjacency/.
Parameters¶
| Parameter | Type | Default | Description |
|---|---|---|---|
window_size |
int |
20 |
Sliding window size for word-word co-occurrence. |
Returns¶
GraphBuildStats — node/edge counts, density, and optional file size.
Example¶
from text4gcn.builder import Frequency
stats = Frequency(dataset_name="R8", dataset_path="data/").tfidf(window_size=20)
print(stats)
Semantic¶
Builds edges based on semantic similarity between words (Word2Vec, BERT, cosine similarity).
class Semantic:
def __init__(self, dataset_name: str, dataset_path: str | os.PathLike[str], verbose: int = 1) -> None
word2vec()¶
def word2vec(
self,
training_algorithm: int,
embedding_dimension: int,
num_epochs: int,
language: str = "english",
threshold: float = 0.7,
seed: int = 1234,
workers: int = 1,
) -> GraphBuildStats
Trains Word2Vec embeddings on the corpus and connects adjacent words whose cosine similarity is at least threshold and whose PMI is positive (DCAI Related Word Filter semantic path). Stop words get no edges; the edge weight is the pair count divided by the largest pair count.
Parameters¶
| Parameter | Type | Default | Description |
|---|---|---|---|
training_algorithm |
int |
— | 1 = skip-gram (as in the DCAI 2022 paper), 0 = CBOW. |
embedding_dimension |
int |
— | Embedding size (e.g. 300). |
num_epochs |
int |
— | Word2Vec training epochs (the paper uses 20). |
language |
str |
"english" |
NLTK stop-word list; stop words get no word–word edges. |
threshold |
float |
0.7 |
Minimum cosine similarity between two adjacent words' embeddings to create an edge. Calibrated on 20 Newsgroups: with 20 epochs, the paper's 0.95 leaves almost no word–word edges. |
seed |
int |
1234 |
Seed of the Word2Vec initialisation. |
workers |
int |
1 |
Word2Vec threads. With 1 the graph is reproducible for a given seed; more threads train faster but vary between runs. |
Returns¶
Example¶
from text4gcn.builder import Semantic
stats = Semantic(dataset_name="R8", dataset_path="data/").word2vec(
training_algorithm=1, # skip-gram
embedding_dimension=300,
num_epochs=20,
threshold=0.7,
)
bert()¶
Embeds each vocabulary word on its own with bert-base-uncased (its [CLS] vector, out of sentence context) and, like word2vec(), connects adjacent non-stop-word words whose cosine similarity is at least threshold and whose PMI is positive. The edge weight is the pair count divided by the largest pair count.
Requirements
bert() needs pip install "text4gcn[bert]" and always uses bert-base-uncased, downloaded on first use. Train on its graph with GNN(..., builder=Builder.Bert).
Parameters¶
| Parameter | Type | Default | Description |
|---|---|---|---|
language |
str |
"english" |
NLTK stop-word list. The model is always bert-base-uncased. |
threshold |
float |
0.95 |
Minimum cosine similarity to create an edge. |
Example¶
from text4gcn.builder import Semantic
Semantic(dataset_name="R8", dataset_path="data/").bert(threshold=0.95)
cosine_similarity()¶
Connects words whose WordNet definitions are similar: the cosine similarity of the TF-IDF vectors of their glosses, saved by TextPipeline. The edge weight is that similarity. Every word with a vector also gets a self-loop (its similarity with itself is 1, above any threshold below 1), counted in word_word_edges. Words without a WordNet definition get no word–word edges, so the builder is meaningful for English only.
Parameters¶
| Parameter | Type | Default | Description |
|---|---|---|---|
threshold |
float |
0.95 |
An edge needs a similarity strictly greater than this. |
Example¶
from text4gcn.builder import Semantic
Semantic(dataset_name="R8", dataset_path="data/").cosine_similarity(threshold=0.90)
Syntactic¶
Builds edges from syntactic structure: dependency parsing or LIWC categories.
class Syntactic:
def __init__(self, dataset_name: str, dataset_path: str | os.PathLike[str], verbose: int = 1) -> None
dependency_parsing()¶
Connects words that have a syntactic dependency relation in the corpus, using Stanford CoreNLP. Each relation except ROOT between two non-stop-word words counts as a pair; as in the other RWF builders, a pair needs positive PMI and its weight is the pair count divided by the largest pair count.
Experimental
Needs pip install "text4gcn[syntactic]" and a local Stanford CoreNLP installation (Java jars), which CI does not run. CoreNLP always parses English; language selects the NLTK stop-word list whose words get no edges.
Parameters¶
| Parameter | Type | Default | Description |
|---|---|---|---|
core_nlp_path |
str |
— | Path to the CoreNLP installation directory. |
language |
str |
"english" |
NLTK stop-word list. CoreNLP always parses English. |
linguistic_inquiry()¶
Connects adjacent words that share at least one LIWC (Linguistic Inquiry and Word Count) category, gated by positive PMI. The edge weight is the pair count divided by the largest pair count.
LIWC dictionary
The LIWC dictionary is proprietary and not distributed with Text4GCN; pass the path to your own .dic file.
Parameters¶
| Parameter | Type | Default | Description |
|---|---|---|---|
liwc_path |
str |
— | Path to the LIWC dictionary file. |
Output layout¶
All builders write to the same directory:
data/
R8.adjacency/
ind.frequency.tfidf.R8.adj ← Frequency.tfidf()
ind.embedding.word2vec.R8.adj ← Semantic.word2vec()
ind.embedding.bert.R8.adj ← Semantic.bert()
ind.cosine.similarity.R8.adj ← Semantic.cosine_similarity()
ind.dependency.parsing.R8.adj ← Syntactic.dependency_parsing()
ind.liwc.R8.adj ← Syntactic.linguistic_inquiry()
The adjacency file is a serialised scipy.sparse matrix. The Builder enum value determines which file GNN loads at training time.
GraphBuildStats¶
Frozen dataclass returned by every builder method (tfidf(), word2vec(), cosine_similarity(), bert(), dependency_parsing(), linguistic_inquiry()).
| Field | Type | Description |
|---|---|---|
n_nodes |
int |
Train docs + vocabulary + test docs. |
n_edges |
int |
Number of stored non-zeros (nnz). |
density |
float |
nnz / n_nodes². |
file_bytes |
int \| None |
Pickled adjacency size on disk, if known. |
builder |
str \| None |
Builder label (e.g. frequency.tfidf). |
dataset_name |
str \| None |
Dataset name. |
path |
str \| None |
Path to the adjacency file. |
word_word_edges |
int \| None |
Stored non-zeros between two word nodes. The builders differ only in these: all keep the same TF-IDF document–word edges. |
print(stats) shows every field with exact counts:
GraphBuildStats(builder='frequency.tfidf', dataset='20NG4', nodes=14,537, edges=…, word_word=…, density=2.15%, size='52.0 MiB')
stats.summary() returns the short form, a plain string:
stats.to_dict() returns the fields as a dict (e.g. for a pandas.DataFrame of several builds).
The builders print that summary under a header line (builder console output, verbose=1 or 2):
text4gcn · Frequency.tfidf("20NG4") · window 20
✓ graph 14,537 nodes · 4.53 M edges (4.26 M word–word) · density 2.15% · 52.0 MiB (4m00s)
verbose (0, 1 default, 2) is given to Frequency, Semantic or Syntactic: 0 is silent, 1 prints the header and summary and adds a progress bar during the slow steps (PMI, word pairs), 2 prints the header and summary without the progress bar. The same lines are appended to {dataset_path}/log/{dataset_name}_dataset.txt.
compute_adjacency_stats() / load_adjacency_stats()¶
def compute_adjacency_stats(
adj: scipy.sparse.spmatrix,
*,
path: str | Path | None = None,
builder: str | None = None,
dataset_name: str | None = None,
word_word_edges: int | None = None,
) -> GraphBuildStats
def load_adjacency_stats(
path: str | Path,
*,
builder: str | None = None,
dataset_name: str | None = None,
) -> GraphBuildStats
compute_adjacency_stats() measures an adjacency matrix in memory (a dense array is converted to sparse); file_bytes is set when path is an existing file. load_adjacency_stats() unpickles a saved adjacency file and measures it. Neither knows which edges are word–word edges, so word_word_edges is None unless passed to compute_adjacency_stats().