Skip to content

Keywords

ruts.corpus.keyness(), ruts.corpus.Keyword

Description

Keyword extraction (keyness) for a target corpus relative to a reference corpus: words that occur significantly more often in the target corpus than in the reference. A standard corpus linguistics tool for comparing genres, authors, translations and periods (AntConc, Sketch Engine, quanteda textstat_keyness).

For every word two values are computed that Gabrielatos and Marchi and Hardie recommend reading together: the log-likelihood \(G^2\) with its p-value (significance of the difference - whether it exists) and Log Ratio (effect size - how large it is). Additionally the chosen measure score is computed and used for sorting. Significance measures (\(G^2\), chi-square, BIC, ELL) are signed: negative if the word is more frequent in the reference; effect measures (%DIFF, Log Ratio, odds ratio) are directional by construction.

The reference can be the Lyashevskaya and Sharoff frequency dictionary (FreqDict): the target words must then be lemmas (WordsExtractor(use_lexemes=True)), they are lowercased with ё replaced by е, and the reference frequency is ipm multiplied by the dictionary corpus size (92 million tokens). Words absent from the dictionary get zero reference frequency.

Words are compared as they are: case, lemmatization and stop words are up to WordsExtractor.

Measures

For a word with frequency \(a\) in a target corpus of size \(c\) and frequency \(b\) in a reference corpus of size \(d\), \(N = c + d\):

Measure Key Formula Description
Log-likelihood log_likelihood \(G^2 = 2\,(a \ln \frac{a}{E_1} + b \ln \frac{b}{E_2})\), \(E_1 = \frac{c\,(a+b)}{N}\), \(E_2 = \frac{d\,(a+b)}{N}\) Rayson and Garside (2000); critical values G2_CRITICAL_VALUES: 3.84 for p < 0.05, 6.63 for p < 0.01, 10.83 for p < 0.001, 15.13 for p < 0.0001
Chi-square chi2 \(\chi^2 = \frac{N\,\max(\lvert a(d-b) - b(c-a) \rvert - N/2,\ 0)^2}{(a+b)(N-a-b)\,c\,d}\) with Yates's correction over the 2×2 contingency table; if the correction exceeds the difference, the statistic is zero
%DIFF diff \(\frac{NF_a - NF_b}{NF_b} \cdot 100\) Gabrielatos and Marchi (2011); \(NF\) - frequency per million words
Log Ratio log_ratio \(\log_2 \frac{NF_a}{NF_b}\) Hardie (2014); one means the word is twice as frequent in the target corpus
BIC bic \(\operatorname{sign}(G^2) \cdot (\lvert G^2 \rvert - \ln N)\) Wilson (2013); in absolute value above 2 - positive evidence of a difference, above 6 - strong, above 10 - very strong; a negative value with \(\lvert G^2 \rvert < \ln N\) means no evidence, not the opposite direction
ELL ell \(\frac{G^2}{N \ln \min(E_1, E_2)}\) Johnson, Culpeper and Rayson (2007); effect size for \(G^2\) from 0 to 1, nan when the minimum expected frequency is below \(e\) - then \(\ln \min(E_1, E_2) < 1\) and the measure exceeds one
Odds ratio odds_ratio \(\frac{a / (c - a)}{b / (d - b)}\) one means equal odds; inf if the word fills the whole target corpus, 0 - the whole reference

A zero frequency in one of the corpora is replaced with 0.5 when computing %DIFF, Log Ratio and the odds ratio (Hardie 2014). The p-value of \(G^2\) is computed from the chi-square distribution with one degree of freedom (calc_p_value). The measures are available as functions calc_log_likelihood, calc_chi2, calc_diff, calc_log_ratio, calc_bic, calc_ell, calc_odds_ratio with arguments (a, b, c, d) from the module ruts.corpus.keyness (from ruts.corpus.keyness import calc_log_likelihood; the name ruts.corpus.keyness in the package is taken by the function of the same name, so importing the whole module does not work); names and descriptions are in ruts.constants.KEYNESS_MEASURES.

Parameters

Parameter Type Default Description
target list[str]/dict[str, int] - Words of the target corpus or their frequencies
reference list[str]/dict[str, float]/FreqDict - Words of the reference corpus, their frequencies or a frequency dictionary
measure str log_likelihood Measure from KEYNESS_MEASURES for score and sorting
min_freq int 1 Minimum frequency of a keyword in its own corpus
positive bool True Positive keywords (more frequent in the target corpus) or negative (more frequent in the reference)
top_n int None Number of keywords; None - all

Result

A list of Keyword named tuples in descending keyness order (ties broken by descending frequency and alphabetically, words with an undefined measure last); pd.DataFrame(keywords) gives a table.

Field Type Description
word str Word
freq_target int Frequency in the target corpus
freq_reference float Frequency in the reference corpus (fractional for a dictionary)
ipm_target float Frequency in the target corpus per million words
ipm_reference float Frequency in the reference corpus per million words
g2 float Signed \(G^2\)
p_value float p-value of \(G^2\)
log_ratio float Log Ratio
score float Value of the chosen measure

Example

Example

from ruts import WordsExtractor
from ruts.corpus import keyness

we = WordsExtractor(use_lexemes=True, lowercase=True)
target = we.extract(
    "Кот сидел на окне и смотрел на птиц. Птицы улетели, и кот уснул на окне. "
    "Завтра кот снова будет сидеть на окне и смотреть на птиц."
)
reference = we.extract(
    "Собака лежала на полу и дремала. Потом собака ела и снова дремала. Завтра собака будет гулять."
)

keyness(target, reference, top_n=1)
# [Keyword(word='кот', freq_target=3, freq_reference=0, ipm_target=115384.61538461539,
#  ipm_reference=0.0, g2=2.8774384815713177, p_value=0.08982881315854577,
#  log_ratio=1.8845227825800641, score=2.8774384815713177)]

[(k.word, round(k.g2, 2)) for k in keyness(target, reference, positive=False, top_n=2)]
# [('собака', -5.79), ('дремать', -3.86)]

# Relative to the frequency dictionary (after FreqDict().download())
from ruts.datasets import FreqDict

[(k.word, round(k.log_ratio, 1)) for k in keyness(target, FreqDict(), min_freq=3, top_n=2)]
# [('кот', 11.5), ('птица', 10.3)]