在Logistic回归中使用排名数据

时间:2014-03-01 17:25:20

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

我将努力学习这些概念,并将最大的赏金放在这上面!我试图在逻辑回归中使用一些排名数据。我想用机器学习来制作一个关于网页是否“好”的简单分类器。这只是一次学习练习,所以我不指望取得好成绩;只是希望学习“过程”和编码技巧。

我已将数据放入.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中将其标准化,以便尽可能地获得最佳效果 我的数据结果?
  • 我正以这种方式运行Logistic回归;我几乎可以肯定我做错了。我正在尝试在网站文本上执行TF-IDF,然后添加其他两个相关列并适合Logistic回归。如果有人能够快速验证我是否正在接受我要在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.."`
    

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

2 个答案:

答案 0 :(得分:5)

我想sklearn.preprocessing.StandardScaler是你想要尝试的第一件事。 StandardScaler将您的所有功能转换为Mean-0-Std-1功能。

  • 这绝对摆脱了你的第一个问题。 AlexaRank将保证在0左右展开并且有限。 (是的,即使像AlexaRank这样的大量83904803289480值也会转换为小的浮点数。当然,结果不会是110000之间的整数,但它们将保持与原始排名相同的顺序。在这种情况下,保持等级有界和标准化将有助于解决您的第二个问题,如下所示。
  • 为了理解为什么规范化会对LR有所帮助,让我们重新审视LR的logit公式。 enter image description here
    在您的情况下,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文件中的原始标头名称。还要注意我们如何使用整个列进行索引。最后,您可以使用X使用numpy.hstack 堆叠这个新矩阵。

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

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

答案 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)

对于使用默认设置的所有内容,您可能无法获得非常好的结果, 但它应该给你一个工作基线来工作。如果您愿意,我可以建议一些通常适合我的参数设置。