Вопрос приходят ли текст A и текст B из одного дистрибутива? как-то плохо определен. Например, эти два вопроса (1,2) можно рассматривать как сгенерированные из одной раздачи (раздача всех вопросов на StackExchange) или из разных раздач (раздача двух разных поддоменов StackExchange). Поэтому неясно, какое свойство вы хотите проверить.
В любом случае, вы можете получить любую тестовую статистику по вашему выбору, аппроксимировать ее распределение в случае одного источника с помощью моделирования и рассчитать p-значение вашего теста.
В качестве игрушечного примера возьмем два небольших корпуса: две случайные статьи из английской Википедии. я сделаю это на питоне
import requests
from bs4 import BeautifulSoup
urls = [
'https://en.wikipedia.org/wiki/Nanjing_(Liao_dynasty)',
'https://en.wikipedia.org/wiki/United_States_Passport_Card'
]
texts = [BeautifulSoup(requests.get(u).text).find('div', {'class': 'mw-parser-output'}).text for u in urls]
Теперь я использую примитивный токенизатор для подсчета отдельных слов в текстах и использую среднеквадратичную разницу в относительных частотах слов в качестве тестовой статистики. Вы можете использовать любую другую статистику, если вы рассчитываете ее последовательно.
import re
from collections import Counter
from copy import deepcopy
TOKEN = re.compile(r'([^\W\d]+|\d+|[^\w\s])')
counters = [Counter(re.findall(TOKEN, t)) for t in texts]
print([sum(c.values()) for c in counters])
# [5068, 4053]: texts are of approximately the same size
def word_freq_rmse(c1, c2):
result = 0
vocab = set(c1.keys()).union(set(c2.keys()))
n1, n2 = sum(c1.values()), sum(c2.values())
n = len(vocab)
for word in vocab:
result += (c1[word]/n1 - c2[word]/n2)**2 / n
return result**0.5
print(word_freq_rmse(*counters))
# rmse is 0.001178, but is this a small or large difference?
Я получаю значение 0,001178, но не знаю, большая ли это разница. Поэтому мне нужно смоделировать распределение этой тестовой статистики при нулевой гипотезе: когда оба текста принадлежат одному и тому же распределению. Чтобы смоделировать это, я объединяю два текста в один, а затем разбиваю их случайным образом и вычисляю свою статистику при сравнении этих двух случайных частей.
import random
tokens = [tok for t in texts for tok in re.findall(TOKEN, t)]
split = sum(counters[0].values())
distribution = []
for i in range(1000):
random.shuffle(tokens)
c1 = Counter(tokens[:split])
c2 = Counter(tokens[split:])
distribution.append(word_freq_rmse(c1, c2))
Теперь я вижу, насколько необычным является значение моей наблюдаемой тестовой статистики при нулевой гипотезе:
observed = word_freq_rmse(*counters)
p_value = sum(x >= observed for x in distribution) / len(distribution)
print(p_value) # it is 0.0
print(observed, max(distribution), sum(distribution) / len(distribution)) # 0.0011 0.0006 0.0004
Мы видим, что когда тексты из одного дистрибутива, моя тестовая статистика в среднем равна 0,0004 и почти никогда не превышает 0,0006, поэтому значение 0,0011 очень необычно, и нулевая гипотеза о том, что два моих текста происходят из одного дистрибутива, должна быть отвергнута.
person
David Dale
schedule
05.11.2020