【问题标题】:sklearn.feature_selection.chi2 returns list of NaN valuessklearn.feature_selection.chi2 返回 NaN 值列表
【发布时间】:2022-01-10 01:11:20
【问题描述】:

我有以下数据集(我将只上传4行的样本,真实的有15,000行):

import pandas as pd
import numpy as np
from sklearn.feature_extraction.text import TfidfVectorizer
import nltk
from nltk.corpus import stopwords
from sklearn.feature_selection import chi2

quotes=["Sip N Shop Come thru right now Marjais PopularNobodies MMR Marjais SipNShop", 
        "I do not know about you but My family and I will not take the Covid19 vaccine anytime soon",
        "MSignorile Immunizations should be mandatory Period In Oklahoma they will not let kids go to school without them It is dangerous otherwise",
        "President Obama spoke in favor of vaccination for children Fox will start telling its viewers to choose against vaccination in 321"]

labels=[0,1,2,0]
dummy = pd.DataFrame({"quote": quotes, "label":labels})

我想应用著名的卡方检验来消除每个类别 (0,1,2) 中不相关单词的数量。其中 0:中性,1:正,2:负。

以下是我的方法(类似于实现的方法here
简而言之,我创建了一个等于语料库长度的 0 的空列表。 0 代表 y = 0 的第一个标签。对于第二个标签(1=正),我将创建一个空列表 1。第三个标签也是如此(2=否定)。

应用此 3 次后(对于每个目标标签),我将拥有三个 3 列表,每个标签具有最相关的单词。这个最终列表将是我的 TF-IDF 矢量化器的新词汇。

def tweeter_tokenizer(tweet):
    return tweet.split(' ')
    
vectorizer = TfidfVectorizer(tokenizer=tweeter_tokenizer, ngram_range=(1,2), stop_words=english_stopwords)
vectorizer.fit(dummy["quote"])
X_train = vectorizer.transform(dummy["quote"])
y_train = dummy["label"]

feature_names = vectorizer.get_feature_names_out()
y_neutral     = np.array([0]*X_train.shape[0])
pValue        = 0.90

chi_neutral, p_neutral   = chi2(X_train, y_neutral)

chi_neutral

chi_neutral 对象是:

数组([南,南,南,南,南,南,南,南,南,南,南,南,南, 南,南,南,南,南,南,南,南,南,南,南,南,南, 南,南,南,南,南,南,南,南,南,南,南,南,南, 南,南,南,南,南,南,南,南,南,南,南,南,南, 南,南,南,南,南,南,南,南,南,南,南,南,南, 南,南,南,南,南,南,南,南,南,南,南,南,南, 南,南])

最后,我想创建一个数据框,该数据框等于每个标签的唯一标记 (feature_names) 的长度。我将只保留 score > pValue 的单词。数据框将向我显示语料库的总令牌中有多少依赖于 0 类(中性)。其余标签将遵循相同的方法(1:正面,2:负面)。

y_df = np.array([0]*X_train.shape[1])
tokens_neutral_dependent = pd.DataFrame({
    "tweet_token": feature_names,
    "chi2_score" : 1-p_neutral,
    "neutral_label": y_df #length = length of feature_names()
})
tokens_neutral_dependent = tokens_neutral_dependent.sort_values(["neutral_label","chi2_score"], ascending=[True,False])
tokens_neutral_dependent = tokens_neutral_dependent[tokens_neutral_dependent["chi2_score"]>pValue]
tokens_neutral_dependent.shape

【问题讨论】:

    标签: python pandas scikit-learn chi-squared


    【解决方案1】:

    我认为在没有附加类的情况下计算卡方统计量并没有真正的意义。代码chi2(X_train, y_neutral) 询问“假设该类和参数是独立的,获得此分布的几率是多少?”但是你展示的所有例子都是同一个类。

    我会建议这样做:

    chi_neutral, p_neutral   = chi2(X_train, y_train)
    

    如果您对特定类之间的卡方统计数据感兴趣,可以先将数据集过滤为仅两个类,然后运行卡方检验。但这一步不是必须的。

    【讨论】:

    • 你好尼克,谢谢你的回答。我试图在 y_train 中应用卡方。但是我怎么知道每个班级哪些令牌更重要。这让我很困惑。
    • @NikSp 您可以将数据过滤到两个类,并仅在一对类上运行卡方。因此,您可以检查 0 类和 1 类之间的卡方统计量。然后您可以运行 0 类和 2 类之间的卡方统计量,这将告诉您它对于该比较有多大用处,依此类推。但我认为这一步完全没有必要——你只是在做特征选择,对吧?
    • 是的,我有 143,000 个标记的词汇表,我想将它们过滤到仅重要的标记。比如5000。另请查看我发布的 Towards Data Science 文章中的附加链接。大幅减少令牌数量的一种方法是执行 chi2 测试。
    • 当然,这是有道理的。我的意思是,如果你对所有类进行卡方检验,你会看到哪些特征对分类任何类有用。因此,一个词可能对于找出类 0 和类 1 之间的区别没有用,但对于识别类 2 很有用。由于您正在进行特征选择,因此您不需要知道哪些词对哪个类有用 - 只是哪个总体而言,功能并不重要。
    • 能否请您澄清一下您在写“功能”时的意思。应用上述 chi2 测试后,我将如何检索这些“特征”? “特征”是语料库引用的吗?因为返回的chi_neutral, p_neutral 等于标记的数量,而不是引号的数量。