如何解决如何验证两个文本数据集是否来自不同的分布?
我有两个文本数据集。每个数据集包含多个序列,每个序列可以包含一个以上的句子。
如何测量两个数据集是否来自同一分布?
目的是仅在两个分布之间的差异具有统计学意义时,才验证从一个分布到另一个分布的转移学习。
我急于使用卡方检验,但考虑到高度的自由度,我不确定是否对文本数据有帮助。
更新: 例: 假设我想训练一个情感分类模型。我在IMDb数据集上训练模型,并在IMDb和Yelp数据集上进行评估。我发现在IMDb上训练的模型在Yelp上仍然表现良好。但是问题是这些数据集有何不同?
训练数据集:https://www.kaggle.com/columbine/imdb-dataset-sentiment-analysis-in-csv-format?select=Train.csv
评估1:https://www.kaggle.com/columbine/imdb-dataset-sentiment-analysis-in-csv-format?select=Valid.csv
评估2:https://www.kaggle.com/omkarsabnis/sentiment-analysis-on-the-yelp-reviews-dataset
现在
- 火车和eval 1有何不同?
- 火车和eval 2有何不同?
- 火车和评估2之间的偶然性是不同吗?统计意义和p值是多少?
解决方法
问题“文本A和文本B是否来自同一分布?” 定义不明确。例如,这两个问题(1,2)可以看作是从同一分布(StackExchange上所有问题的分布)或不同分布(StackExchange的两个不同子域的分布)生成的。因此,尚不清楚您要测试的属性是什么。
无论如何,您都可以得出自己选择的任何测试统计信息,通过仿真来估计其分布(在“单一来源”的情况下),并计算测试的p值。
作为一个玩具示例,让我们以两个小型语料库为例:来自英语Wikipedia的两篇随机文章。我将在Python中完成
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的值非常不寻常,并且我的两个文本源自相同分布的原假设应该被拒绝。
,我写了一篇与您的问题相似但不完全相同的文章。 https://towardsdatascience.com/a-new-way-to-bow-analysis-feature-engineering-part1-e012eba90ef
我要解决的问题是检查单词是否在类别或标签之间具有不同的(重要的)分布。
您的问题与我上面提到的问题有一些相似之处。
- 您要比较两个数据集来源,可以将它们视为两个不同的类别
- 此外,要比较数据源,您将不得不比较单词,因为不能直接比较句子
因此,我对此的建议解决方案是:
- 使用count-vectorizer在两个数据集中创建单词特征,并从每个数据集中获取前X个单词
- 假设您的单词总数为N,现在初始化count = 0并开始比较每个单词的分布,如果差异很大,则增加计数器。另外,在某些情况下,一个单词仅存在于一个数据集中,这是一个很好的新词,这意味着它表明它是一个与众不同的功能,因此,这也增加了计数
- 假设总数为n。现在,较低的是N / N比,类似的两个文本是,反之亦然
此外,要验证这种方法-如果n / N比率接近于0,则表明两个数据源相似,这也将来自一个源的数据分为两个(随机采样)并运行上述分析。是这种情况。
请让我知道此方法是否有效,如果您认为此方法有任何缺陷,我也想考虑一下并尝试发展它。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。