您的位置:首页 > 其它

Kaggle比赛-Otto Group Product Classification-打败一半参赛队伍的简单解法

2019-05-04 14:16 351 查看
                     

简介

Otto Group Product Classification Challenge是Kaggle上目前正在进行的一个比赛,目前已1000+队伍参赛,由Otto公司赞助1W美刀,数据也是来自于该公司的产品,提供了train.csv、test.csv、samplesubmission.csv三份数据。train.csv里包含了6万多个样本,每个样本有一个id,93个特征值feat_1~feat_93,以及类别target,一共9种类别:class_1~class_9。test.csv里有14万多测试样本,只有id以及93个特征,参赛者的任务是对这些样本分类。

提交结果的格式

官网上给出的格式:

id,Class_1,Class_2,Class_3,Class_4,Class_5,Class_6,Class_7,Class_8,Class_9        1,0.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,0.0        2,0.0,0.2,0.3,0.3,0.0,0.0,0.1,0.1,0.0
  • 1
  • 2
  • 3
也就是说,可以不用给出确切的类别,给出属于各个类别的概率也行。这一点很重要,我一开始没注意看,浪费了许多精力瞎折腾。所以但凡比赛,官网给出的信息最好都仔细看一遍。

评分标准

评分的公式见:这里

我稍微解释一下这条公式,i表示样本,j表示类别。Pij代表第i个样本属于类别j的概率,如果第i个样本真的属于类别j,则yij等于1,否则为0。

假如你将所有的测试样本都正确分类,所有pij都是1,那每个log(pij)都是0,最终的logloss也是0。

假如第1个样本本来是属于1类别的,但是你给它的类别概率pij=0.1,那logloss就会累加上log(0.1)这一项。我们知道这一项是负数,而且pij越小,负得越多,如果pij=0,将是无穷。这会导致这种情况:你分错了一个,logloss就是无穷。这当然不合理,为了避免这一情况,官方是这样处理的:

也就是说最小不会小于10^-15。

开始解题

废话终于说完,进入主题。下面讲一个很naive的solution,基本上不用动脑,只要会简单地使用sklearn、numpy,就能打败目前一半的参赛队伍。

代码放在我的github上wepe/Kaggle-Solution,分几部分来讲:

数据预处理

严格来说,我并没有做多少数据预处理的工作。只是一些加载数据的函数,分别是
loadTrainSet()和loadTestSet(),加载训练数据集和测试数据集。代码如下,里面顺便做了归一化以及零均值(这里不做standardize差别也不大)。

#load train setdef loadTrainSet():    traindata = []    trainlabel = []    table = {"Class_1":1,"Class_2":2,"Class_3":3,"Class_4":4,"Class_5":5,"Class_6":6,"Class_7":7,"Class_8":8,"Class_9":9}    with open("train.csv") as f:        rows = csv.reader(f)        rows.next()        for row in rows:            l = []            for i in range(1,94):                l.append(int(row[i]))            traindata.append(l)            trainlabel.append(table.get(row[-1]))    f.close() &
4000
nbsp;  traindata = np.array(traindata,dtype="float")    trainlabel = np.array(trainlabel,dtype="int")    #Standardize(zero-mean,nomalization)    mean = traindata.mean(axis=0)    std = traindata.std(axis=0)    traindata = (traindata - mean)/std    #shuffle the data    randomIndex = [i for i in xrange(len(trainlabel))]    random.shuffle(randomIndex)    traindata = traindata[randomIndex]    trainlabel = trainlabel[randomIndex]    return traindata,trainlabel#load test setdef loadTestSet():    testdata = []    with open("test.csv") as f:        rows = csv.reader(f)        rows.next()        for row in rows:            l = []            for i in range(1,94):                l.append(int(row[i]))            testdata.append(l)    f.close()    testdata = np.array(testdata,dtype="float")    #Standardize(zero-mean,nomalization)    mean = testdata.mean(axis=0)    std = testdata.std(axis=0)    testdata = (testdata - mean)/std    return testdata
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
代码挺长的,但其实都是些简单的读取和处理工作。(如果不想写这么繁琐的代码,可以试试数据分析包pandas,几行代码完成这些工作)。

模型评估

模型评估一般都是从训练数据集中分出一部分来做validation,一般我们是用validation accuracy来评估的(如上所述),但是这个比赛既然官方给出了评估公式,我们就根据这个公式写个评估函数:

#Evaluation function#Refer to:https://www.kaggle.com/c/otto-group-product-classification-challenge/details/evaluationdef evaluation(label,pred_label):    num = len(label)    logloss = 0.0    for i in range(num):        p = max(min(pred_label[i][label[i]-1],1-10**(-15)),10**(-15))        logloss += np.log(p)    logloss = -1*logloss/num    return logloss
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
以上三个函数loadTrainSet()、loadTestSet()、evaluation()我都放在代码文件preprocess.py中,此外在该文件中还定义了一个saveResult()函数,根据test set的预测类别test_label生成一个用于提交结果的submission.csv文件。

分类算法

直接调用sklearn里面的随机森林,参数调节:随便调了几次决策树的数目,可以使logloss达到0.5左右,这个得分目前已经打败了一半的参赛队伍。

def rf(train_data,train_label,val_data,val_label,test_data,name="RandomForest_submission.csv"):    print "Start training Random forest..."    rfClf = RandomForestClassifier(n_estimators=400,n_jobs=-1)    rfClf.fit(train_data,train_label)    #evaluate on validation set    val_pred_label = rfClf.predict_proba(val_data)    logloss = preprocess.evaluation(val_label,val_pred_label)    print "logloss of validation set:",logloss    print "Start classify test set..."    test_label = rfClf.predict_proba(test_data)    preprocess.saveResult(test_label,filename = name)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
这个函数的参数val_data就是验证集数据,从train.csv里面取出6000个构成,大约占1/10的数据。

这部分的代码放在文件RandomForest.py中。

有兴趣的去我github获取代码试试吧。Have Fun!

============

by wepon

           
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: