【问题标题】:Using ranking data in Logistic Regression在逻辑回归中使用排名数据
【发布时间】:2014-04-02 18:50:37
【问题描述】:

当我努力学习这些概念时,我将为此付出最大的努力!我正在尝试在逻辑回归中使用一些排名数据。我想使用机器学习来制作一个简单的分类器来判断网页是否“好”。这只是一个学习练习,所以我不期望有很好的结果;只是希望学习“过程”和编码技术。

我已将数据放入 .csv 中,如下所示:

URL WebsiteText AlexaRank GooglePageRank

在我的测试 CSV 中我们有:

URL WebsiteText AlexaRank GooglePageRank Label

标签是一个二进制分类,用 1 表示“好”或用 0 表示“坏”。

我目前仅使用网站文本运行我的 LR;我在上面运行 TF-IDF。

我有两个问题需要帮助。我将对这个问题给予最大的赏金并将其授予最佳答案,因为这是我需要一些好的帮助,所以我和其他人可以学习。

  • 如何标准化我的 AlexaRank 排名数据?我有一套 10,000 个网页,我拥有所有这些网页的 Alexa 排名; 但是他们没有排名1-10,000。他们被排除在外 整个互联网,所以虽然http://www.google.com 可能排名#1http://www.notasite.com 可能排名#83904803289480。我如何能 在 Scikit 学习中对此进行规范化,以获得最佳效果 我的数据结果?
  • 我正在以这种方式运行我的逻辑回归;我几乎可以肯定我做错了。我正在尝试对网站文本进行 TF-IDF,然后添加另外两个相关列并拟合逻辑回归。如果有人能快速验证我是否正确地接受了我想在我的 LR 中使用的三列,我将不胜感激。任何和所有关于我如何提高自己的反馈也将在这里受到赞赏。

    loadData = lambda f: np.genfromtxt(open(f,'r'), delimiter=' ')
    
    print "loading data.."
    traindata = list(np.array(p.read_table('train.tsv'))[:,2])#Reading WebsiteText column for TF-IDF.
    testdata = list(np.array(p.read_table('test.tsv'))[:,2])
    y = np.array(p.read_table('train.tsv'))[:,-1] #reading label
    
    tfv = TfidfVectorizer(min_df=3,  max_features=None, strip_accents='unicode', analyzer='word',
    
    token_pattern=r'\w{1,}', ngram_range=(1, 2), use_idf=1, smooth_idf=1,sublinear_tf=1)
    
    rd = lm.LogisticRegression(penalty='l2', dual=True, tol=0.0001, C=1, fit_intercept=True,    intercept_scaling=1.0, class_weight=None, random_state=None)
    
    X_all = traindata + testdata
    lentrain = len(traindata)
    
    print "fitting pipeline"
    tfv.fit(X_all)
    print "transforming data"
    X_all = tfv.transform(X_all)
    X = X_all[:lentrain]
    X_test = X_all[lentrain:]
    
    print "20 Fold CV Score: ", np.mean(cross_validation.cross_val_score(rd, X, y, cv=20, scoring='roc_auc'))
    
    #Add Two Integer Columns
    AlexaAndGoogleTrainData = list(np.array(p.read_table('train.tsv'))[2:,3])#Not sure if I am doing this correctly. Expecting it to contain AlexaRank and GooglePageRank columns.
    AlexaAndGoogleTestData = list(np.array(p.read_table('test.tsv'))[2:,3])
    AllAlexaAndGoogleInfo = AlexaAndGoogleTestData + AlexaAndGoogleTrainData
    
    #Add two columns to X.
    X = np.append(X, AllAlexaAndGoogleInfo, 1) #Think I have done this incorrectly.
    
    print "training on full data"
    rd.fit(X,y)
    pred = rd.predict_proba(X_test)[:,1]
    testfile = p.read_csv('test.tsv', sep="\t", na_values=['?'], index_col=1)
    pred_df = p.DataFrame(pred, index=testfile.index, columns=['label'])
    pred_df.to_csv('benchmark.csv')
        print "submission file created.."`
    

非常感谢您的所有反馈 - 如果您需要任何进一步的信息,请发布!

【问题讨论】:

  • 只取排名的日志。这将其降低到了术语频率特征的典型范围,并且它在数值上比均值中心更稳定。之后您仍然可以标准化/标准化。
  • 您的火车文件中没有标签列?错字?

标签: python algorithm machine-learning artificial-intelligence scikit-learn


【解决方案1】:

我猜sklearn.preprocessing.StandardScaler 将是您想尝试的第一件事。 StandardScaler 将您的所有特征转换为 Mean-0-Std-1 特征。

  • 这绝对可以解决您的第一个问题。 AlexaRank 将保证分布在 0 附近并有界。 (是的,即使像 83904803289480 这样的大量 AlexaRank 值也会转换为小的浮点数)。当然,结果不会是110000 之间的整数,但它们将保持与原始排名相同的顺序。在这种情况下,保持排名有界和标准化将有助于解决您的第二个问题,如下所示。
  • 为了理解为什么归一化有助于 LR,让我们重新审视一下 LR 的 logit 公式。
    在您的情况下,X1、X2、X3 是三个 TF-IDF 功能,X4、X5 是 Alexa/Google 排名相关的功能。现在,方程的线性形式表明,系数表示 y 的 logit 变化与变量 一个单位 的变化。想想当你的 X4 保持在一个巨大的排名值时会发生什么,比如83904803289480。在这种情况下,Alexa Rank 变量支配您的 LR 拟合,TF-IDF 值的微小变化对 LR 拟合几乎没有影响。现在有人可能会认为系数应该能够调整为小/大值以解释这些特征之间的差异。不是在这种情况下 --- 重要的不仅是变量的大小,还有它们的范围。 Alexa Rank 的范围肯定很大,在这种情况下绝对应该主导你的 LR 适合度。因此,我猜想使用 StandardScaler 对所有变量进行归一化以调整它们的范围会提高拟合度。

以下是缩放X 矩阵的方法。

sc = proprocessing.StandardScaler().fit(X)
X = sc.transform(X)

不要忘记使用相同的缩放器来转换X_test

X_test = sc.transform(X_test)

现在您可以使用拟合程序等。

rd.fit(X, y)
re.predict_proba(X_test)

查看更多关于 sklearn 预处理的信息:http://scikit-learn.org/stable/modules/preprocessing.html

编辑:解析和列合并部分可以使用pandas轻松完成,即无需将矩阵转换为列表然后附加它们。此外,pandas 数据框可以直接通过其列名进行索引。

AlexaAndGoogleTrainData = p.read_table('train.tsv', header=0)[["AlexaRank", "GooglePageRank"]]
AlexaAndGoogleTestData = p.read_table('test.tsv', header=0)[["AlexaRank", "GooglePageRank"]]
AllAlexaAndGoogleInfo = AlexaAndGoogleTestData.append(AlexaAndGoogleTrainData)

请注意,我们将 header=0 参数传递给 read_table 以维护 tsv 文件中的原始标题名称。还要注意我们如何使用整个列集进行索引。最后,您可以使用numpy.hstack 将这个新矩阵与X堆叠

X = np.hstack((X, AllAlexaAndGoogleInfo))

hstack 水平组合两个多维数组结构,只要它们的长度相同。

【讨论】:

  • 非常感谢您的回答;真正的信息和教育。对此,我真的非常感激!还有一个简单的问题——如何将我的 TF-IDF numpy 数组与包含我的排名值的 numpy 数组结合起来。我曾尝试在我的代码中执行此操作,但不幸的是,我相信我完全错误地执行了此操作。非常感谢,+1。
  • 我已编辑响应以解决索引/附加问题。
  • 太棒了。太感谢了! :)
  • 赏金好吗? :) 开玩笑的
  • 放心我会在符合条件的时候添加!谢谢你:)
【解决方案2】:

关于数字等级的归一化,scikit StandardScaler 或对数变换(或两者)应该足够好。

为了建立一个工作管道,我发现使用 Pandas 包和 sklearn.pipeline 实用程序可以极大地提高我的理智。这是一个简单的脚本,应该可以满足您的需求。

首先是几个我似乎总是需要的实用类。在sklearn.pipelinesklearn.utilities 中有类似的东西会很好。

from sklearn import base
class Columns(base.TransformerMixin, base.BaseEstimator):
    def __init__(self, columns):
        super(Columns, self).__init__()
        self.columns_ = columns
    def fit(self, *args, **kwargs):
        return self
    def transform(self, X, *args, **kwargs):
        return X[self.columns_]

class Text(base.TransformerMixin, base.BaseEstimator):
    def fit(self, *args, **kwargs):
        return self
    def transform(self, X, *args, **kwargs):
        return (X.apply("\t".join, axis=1, raw=False))

现在设置管道。 我使用了逻辑回归的SGDClassifier 实现,因为它对于文本分类等高维数据往往更有效,而且我通常发现铰链损失通常比逻辑回归提供更好的结果。

from sklearn import linear_model as lin
from sklearn import  metrics
from sklearn.feature_extraction import text as txt
from sklearn.pipeline import Pipeline, FeatureUnion
from sklearn.preprocessing import StandardScaler
from sklearn import preprocessing as prep
import numpy as np
from pandas.io import parsers
import pandas as pd

pipe = Pipeline([
    ('feat', FeatureUnion([
        ('txt', Pipeline([
            ('txtcols', Columns(["WebsiteText"])),
            ('totxt', Text()),
            ('vect', txt.TfidfVectorizer()),
            ])),
        ('num', Pipeline([
            ('numcols', Columns(["AlexaRank", "GooglePageRank"])),
            ('scale', prep.StandardScaler()),
            ])),
        ])),
    ('clf', lin.SGDClassifier(loss="log")),
    ])

接下来训练模型:

train=parsers.read_csv("train.csv")
pipe.fit(train, train.Label)

最后评估测试数据:

test=parsers.read_csv("test.csv")
tstlbl=np.array(test.Label)

print pipe.score(test, tstlbl)

pred = pipe.predict(test)
print metrics.confusion_matrix(tstlbl, pred)
print metrics.classification_report(tstlbl, pred)
print metrics.f1_score(tstlbl, pred)

prob = pipe.decision_function(test)
print metrics.roc_auc_score(tstlbl, prob)
print metrics.average_precision_score(tstlbl, prob)

使用这样的默认设置,你可能不会得到很好的结果, 但它应该给你一个工作基线。如果您愿意,我可以建议一些通常对我有用的参数设置。

【讨论】:

    猜你喜欢
    • 2016-05-17
    • 2015-06-30
    • 2020-12-09
    • 2017-01-15
    • 1970-01-01
    • 2019-03-02
    • 2015-05-15
    • 1970-01-01
    • 2018-06-14
    相关资源
    最近更新 更多