在逻辑回归中使用排名数据
我会把这个问题的悬赏提到最高,因为我在学习这些概念时遇到了困难!我想在逻辑回归中使用一些排名数据。我希望利用机器学习来简单判断一个网页是“好”的还是“不好”的。这只是一个学习练习,所以我不期待得到很好的结果;我只是希望能学到“过程”和编码技巧。
我把我的数据放在了一个.csv文件里,内容如下:
URL WebsiteText AlexaRank GooglePageRank
在我的测试CSV中,我们有:
URL WebsiteText AlexaRank GooglePageRank Label
标签是一个二分类,表示“好”的用1表示,“不好”的用0表示。
目前我只用网站的文本在运行逻辑回归;我对这些文本进行了TF-IDF处理。
我有两个问题需要帮助。我会把这个问题的悬赏提到最高,并奖励给最好的回答,因为这是我希望能得到好的帮助的地方,这样我和其他人都可以学习。
- 我该如何规范化我的Alexa排名数据?我有一组10,000个网页,所有网页的Alexa排名我都有;但是它们的排名不是
1-10,000
。它们是相对于整个互联网的排名,所以虽然http://www.google.com
可能排名#1
,但http://www.notasite.com
可能排名#83904803289480
。我该如何在Scikit learn中规范化这些数据,以便从我的数据中获得最佳结果? 我这样运行我的逻辑回归;我几乎可以肯定我做错了。我试图对网站文本进行TF-IDF处理,然后添加另外两个相关的列,并拟合逻辑回归。如果有人能快速确认我是否正确地将我想在逻辑回归中使用的三列数据输入,那将非常感激。任何关于我如何改进自己的反馈也非常欢迎。
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 个回答
关于数字排名的标准化,可以使用scikit的StandardScaler
或者对数变换(或者两者结合),效果都不错。
在建立一个有效的工作流程时,我发现使用Pandas这个包和sklearn.pipeline
的工具可以让我更加清晰。下面是一个简单的脚本,应该能满足你的需求。
首先是一些我总是需要的工具类。如果sklearn.pipeline
或sklearn.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)
如果你一开始就用默认设置,可能不会得到很好的结果,但这应该能给你一个可以开始的基础。如果你需要,我可以推荐一些通常对我有效的参数设置。
我想你可以先试试 sklearn.preprocessing.StandardScaler
。这个工具可以把你所有的特征转换成均值为0、标准差为1的特征。
- 这样做肯定能解决你第一个问题。
AlexaRank
会被调整到围绕0的范围内(是的,即使是像83904803289480
这样巨大的AlexaRank
值也会被转换成小的浮点数)。当然,结果不会是介于1
和10000
之间的整数,但它们的顺序和原来的排名是一样的。在这种情况下,保持排名的范围和标准化会帮助解决你的第二个问题,方法如下。 - 为了理解为什么标准化对逻辑回归(LR)有帮助,我们来回顾一下逻辑回归的公式。
在你的例子中,X1、X2、X3 是三个 TF-IDF 特征,而 X4、X5 是与 Alexa/Google 排名相关的特征。现在,这个线性方程的形式表明,系数表示 y 的对数几率随着某个变量变化一个单位时的变化。想象一下,当你的 X4 固定在一个巨大的排名值,比如83904803289480
时,会发生什么。在这种情况下,Alexa Rank 变量会 主导 你的逻辑回归模型,而 TF-IDF 值的微小变化几乎对逻辑回归模型没有影响。有人可能会认为,系数应该能够调整以适应这些特征之间的大小差异。但在这种情况下并不是这样——不仅变量的大小重要,它们的 范围 也很重要。Alexa Rank 的范围确实很大,因此在这种情况下肯定会主导你的逻辑回归模型。因此,我认为使用 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)
注意,我们在 read_table 中传递了 header=0
参数,以保持来自 tsv 文件的原始列名。同时注意我们如何使用整个列集进行索引。最后,你可以使用 numpy.hstack
将这个新矩阵与 X
进行 堆叠。
X = np.hstack((X, AllAlexaAndGoogleInfo))
hstack
可以将两个多维数组结构水平合并,前提是它们的长度相同。