Тук е представено използването на йерархична клъстеризация за класификация на текст спрямо съдържанието му.
От текста се извличат всички "признаци" (tokens), след което се изчислява честотата им в текста. Нормата на един признак се дефинира като евклидовата норма на вектора с координати честоти на срещане на този признак в различните текстове, т.е. признаците се отъждествяват с вектори в $\mathbb{R}^n$, където $n$ е броят анализирани текстове. Всеки признак се смята, че принадлежи на този текст, на който съответства най-голямата координата. По-долу за това е използван терминът "Dominant text"
Пет текста са групирани в три клъстъра:
Янис Василев, 02.07.2018
# Workspace preparation
library('ggplot2')
options(repr.plot.width=6, repr.plot.height=6)
source('tokenize.R')
source('statistics.R')
source('cleanup.R')
source('clusterize.R')
source('plot.R')
source('classification.R')
# Extract a token data frame from the literary work list
tokens <- tokenizeWorks(c(
'Й. Йовков - Шибил',
'Й. Йовков - Индже',
'Наказателен кодекс, глави 1-10',
'Уикипедия - ПФК Ботев (Пловдив)',
'Уикипедия - ПФК Левски (София)'
))
# Display the top ten tokens for each of the works
topWordsTable(tokens, 10)
(1) Й. Йовков - Шибил | (2) Й. Йовков - Индже | (3) Наказателен кодекс, глави 1-10 | (4) Уикипедия - ПФК Ботев (Пловдив) | (5) Уикипедия - ПФК Левски (София) |
---|---|---|---|---|
и | и | от | на | на |
се | се | г | и | и |
на | на | на | в | в |
да | да | бр | за | левски |
си | индже | дв | от | през |
не | си | в | е | е |
в | му | изм | се | с |
беше | не | и | ботев | от |
шибил | беше | е | с | за |
от | от | се | през | г |
# Clean and clusterize the tokens.
# The cleaning is done by removing the 15 tokens that are cumulatively most common
# to all of the works and then cleaning out outliers, i.e. vectors whose projections
# on the coordinate axes fail the z-test with a confidence value of 0.9.
cleanedTokens <- clearOutliers(clearCommon(tokens, 15), 0.9)
# Clusterize the data into three clusters using hierarchical clustering with complete linkage
mtx <- extractCoordinateMatrix(cleanedTokens)
clusters <- cutree(hclust(dist(mtx), method='complete'), k=3)
clusteredTokens <- analyzeClusterization(cleanedTokens, clusters)
# Plot the PCA-based projection into the plane
plotPCAProjections(clusteredTokens)
# Plot the coordinate projections of (2) and (3)
plotTwoLevels(clusteredTokens, 2:3)
# Use single-linkage clustering on the same data.
# This example shows that the clusterization method dramatically affects the outcome.
clustersSingle <- cutree(hclust(dist(mtx), method='single'), k=3)
clusteredTokensSingle <- analyzeClusterization(cleanedTokens, clustersSingle)
plotPCAProjections(clusteredTokensSingle)
# Use classical (Lloyd) k-means clustering on the same data.
modelLloyd <- kmeans(mtx, 3, algorithm='Lloyd')
clusteredTokensLloyd <- analyzeClusterization(cleanedTokens, modelLloyd$cluster)
plotPCAProjections(clusteredTokensLloyd)
# Use MacQueen k-means clustering on the same data.
modelMacQueen <- kmeans(mtx, 3, algorithm='MacQueen')
clusteredTokensMacQueen <- analyzeClusterization(cleanedTokens, modelMacQueen$cluster)
plotPCAProjections(clusteredTokensMacQueen)
scaleToSmallNumbers <- function (value) {
value * 10^(-floor(log10(value)))
}
# Compare the within-cluster sums of squares
withinss <- data.frame(Lloyd=modelLloyd$withinss, MacQueen=modelMacQueen$withinss)
scaleToSmallNumbers(withinss)
Lloyd | MacQueen |
---|---|
7.828887 | 8.548649 |
2.074166 | 5.410549 |
2.680655 | 3.722780 |
# Use the complete-linkage clusterization to classify a few texts for cross-validation
source('classification.R')
classifyWorks(
clusteredTokens,
c(
'Й. Йовков - Кошута',
'Закон за амнистия и връщане на отнети имущества',
'Уикипедия - Георги Аспарухов'
)
)
work | cluster |
---|---|
Й. Йовков - Кошута | (1), (2) |
Закон за амнистия и връщане на отнети имущества | (3) |
Уикипедия - Георги Аспарухов | (4), (5) |