最近阿里巴巴办了个数据挖掘竞赛-阿里巴巴大数据竞赛,题目是根据天猫用户4个月的行为记录来预测用户下一个月会买什么东西,参赛对象为高校在校学生。由于奖金数额十分巨大,因此比赛规模可以说是空前绝后的,短短2周就有4000多支队伍报名。比赛过程中,每队每周可以提交一次结果,组委会每周日统一计算各队的分数并公布排行榜(top 500)。
噢,忘了说了这篇文章是关于R语言抓数据以及画图的,与比赛木有关系。本篇的内容纯粹just for fun,不具任何实际价值。是对我最近在cos.name上混来的一些R语言技巧的复习。
好了继续。当然我也参加了比赛,但是很不幸第二周就被挤了出来,于是乎对着这个top 500看了好久,想了好久,睡了好久……
由于参赛队员都是在校学生,而且又是规模空前,几乎全国稍微有点名气的学校都参加了,那么这些学校的表现如何呢?一所大学的综合排名能否很好的表现在比赛中呢?这次的文章就在尝试能否用数据来帮助理解前面这些问题。
首先我们需要获取这份榜单,地址是:
http://102.alibaba.com/competition/addDiscovery/totalRank.htm。
打开发现每页只能显示20支队伍,一共25页。一开始的想法是利用R的XML包,读取HTML TABLE,但是点击第2页的时候,发现网址居然是不会变化的,因此就没有办法根据网址一页一页下载下来。怀疑应该是在你点击下一页的时候,通过一个API获取下一页的信息,再利用javascript来更新表格。
此时派chrome上场,在页面上点右键-审查元素,打开develop tools:
选择Network,然后在排行榜的页面庄重的点"下一页"。然后developer tools就会抓到刚刚点了"下一页"之后发生的http请求。
http://102.alibaba.com/competition/addDiscovery/queryTotalRank.json?就是网页获取排名数据的API了,使用POST方法,带上pageIndex以及pageSize两个参数,就可以获取排名信息。接下来就要请RCurl上场了。
1 2 3 |
library(RCurl) library(rjson) library(plyr) |
?
1 2 3 4 5 6 7 8 9 10 |
api <- "http://102.alibaba.com/competition/addDiscovery/queryTotalRank.json" # 发现其实可以抓到所有队伍的排名,不止是top 500,把pageSize设很大就行了 result <- postForm(api, pageIndex = 1, pageSize = 5000) resjson <- fromJSON(result) ranks <- (resjson$returnValue$datas) leaderBoard <- ldply(ranks, unlist) leaderBoard <- leaderBoard[, c("rank", "teamName", "university", "score", "dateString")] leaderBoard$score <- as.numeric(leaderBoard$score) leaderBoard$rank <- as.integer(leaderBoard$rank) head(leaderBoard) |
? |
teamName |
university |
score |
dateString |
1 |
cucyyyy |
中国传媒大学 |
0.0717 |
2014-03-23 |
2 |
花莲 |
南京大学 |
0.0694 |
2014-03-23 |
3 |
CUCkdd |
中国传媒大学 |
0.0692 |
2014-03-23 |
4 |
WYZ |
清华大学 |
0.0685 |
2014-03-23 |
5 |
車輪戦 |
哈尔滨工业大学 |
0.0684 |
2014-03-16 |
先来看看各个学校都有多少队参加比赛。
1 2 3 4 |
library(ggplot2) # 因为这次想用刚学的ggplot2画图,这里设定下ggplot2的全局参数, # 把字体设为宋体,以正常显示中文 theme_set(theme_grey(base_family = "Songti SC", base_size = 15)) |
?
1 2 3 4 5 6 7 8 |
school_summary <- ddply(leaderBoard, .(university), function(x) c(num_teams=nrow(x))) school_summary <- school_summary[order(school_summary$num_teams,decreasing=T),] school_summary$university <- factor(school_summary$university,levels=school_summary$university) ggplot(school_summary[1:10,], aes(x=university, y=num_teams)) + geom_bar(stat="identity", fill="steelblue") + geom_text(aes(label=num_teams, vjust=-.3)) + labs(title="参赛队伍数最多的10所大学\n",x="",y="参赛队伍数") + theme(axis.text=element_text(size=14,angle=20)) |
看来浙大很具主场优势啊,中科院也是来势汹汹。这里参赛队伍数是报名并且成功提交过结果的队伍数,截止3.23凌晨,共有1383队提交过结果。
那么如何衡量学校的表现呢?先来看看哪些学校的牛人最牛。我这里用的方法是计算每个学校最强的5支队伍的平均分数。
1 2 3 4 5 6 7 8 9 10 |
mean_top5 <- ddply(leaderBoard,.(university), function(x){ scores <- x$score scores <- scores[order(scores,decreasing=T)] c(average=mean(scores[1:5],na.rm=T), num_teams=nrow(x)) }) mean_top5 <- mean_top5[order(mean_top5$average,decreasing=T),] mean_top5 <- mean_top5[mean_top5$num_team >= 5,] rownames(mean_top5) <- 1:nrow(mean_top5) mean_top5 |
为了减少极端值的影响,这里把参赛队伍数少于5的学校给过滤掉了。
根据每个学校前5名平均分排序
? |
university |
average |
num_teams |
1 |
哈尔滨工业大学 |
0.0662 |
45 |
2 |
浙江大学 |
0.0661 |
97 |
3 |
清华大学 |
0.0651 |
37 |
4 |
南京大学 |
0.0645 |
40 |
5 |
中国科学院大学 |
0.0645 |
76 |
6 |
中国科学技术大学 |
0.0643 |
47 |
7 |
北京邮电大学 |
0.0639 |
87 |
8 |
北京理工大学 |
0.0628 |
25 |
9 |
华中师范大学 |
0.0623 |
10 |
10 |
北京航空航天大学 |
0.0622 |
22 |
11 |
北京大学 |
0.0620 |
39 |
12 |
电子科技大学 |
0.0619 |
56 |
13 |
西南交通大学 |
0.0613 |
11 |
14 |
大连理工大学 |
0.0604 |
19 |
15 |
西安电子科技大学 |
0.0600 |
37 |
16 |
中山大学 |
0.0597 |
35 |
17 |
华南理工大学 |
0.0591 |
28 |
18 |
山东大学 |
0.0590 |
14 |
19 |
武汉大学 |
0.0588 |
19 |
20 |
香港科技大学 |
0.0574 |
15 |
21 |
东南大学 |
0.0571 |
27 |
22 |
中国人民大学 |
0.0570 |
9 |
23 |
厦门大学 |
0.0569 |
15 |
24 |
华东师范大学 |
0.0565 |
14 |
25 |
上海交通大学 |
0.0565 |
20 |
26 |
华中科技大学 |
0.0562 |
35 |
27 |
东北大学 |
0.0559 |
17 |
28 |
同济大学 |
0.0557 |
15 |
29 |
复旦大学 |
0.0530 |
25 |
30 |
南开大学 |
0.0520 |
11 |
31 |
天津大学 |
0.0498 |
12 |
32 |
西安交通大学 |
0.0480 |
12 |
33 |
东华大学 |
0.0467 |
11 |
34 |
广东工业大学 |
0.0460 |
8 |
35 |
北京交通大学 |
0.0459 |
7 |
36 |
北京师范大学 |
0.0459 |
6 |
37 |
湖南大学 |
0.0450 |
6 |
38 |
南京邮电大学 |
0.0440 |
8 |
39 |
西北农林科技大学 |
0.0430 |
5 |
40 |
西北工业大学 |
0.0426 |
8 |
41 |
南京航空航天大学 |
0.0413 |
6 |
42 |
中国科学院软件研究所 |
0.0403 |
5 |
43 |
燕山大学 |
0.0378 |
5 |
44 |
吉林大学 |
0.0366 |
6 |
45 |
北京工业大学 |
0.0358 |
5 |
46 |
哈尔滨工业大学(威海) |
0.0356 |
6 |
47 |
中南大学 |
0.0315 |
6 |
48 |
浙江工商大学 |
0.0283 |
5 |
49 |
四川大学 |
0.0267 |
6 |
50 |
武汉理工大学 |
0.0209 |
6 |
51 |
福建师范大学 |
0.0041 |
5 |
上面的学校排名符合您心目中的预期吗?
那么如何去衡量一个学校所有队伍的综合表现呢?当分数的分布有偏的时候,不太好直接使用全部队伍得分的平均数来对比两个学校的表现,而且各个学校参赛队伍数差异很大。中位数是个不错的衡量指标,但它会忽略这个学校最强和最弱的这两群学生。
一个比较直觉的想法是,如果这个学校所有队伍的排名整体比较靠前,则该学校整体实力较强。如果这个学校所有队伍的排名整体比较靠后,则该学校整体实力较弱。
这里可以拿两所学校做个对比。为何会选这两所学校呢?很简单,博主来自于厦大,另外下面那所学校是随机挑的。
1 2 3 4 5 6 |
tsinghua <- leaderBoard[leaderBoard$university=="清华大学",] xmu <- leaderBoard[leaderBoard$university=="厦门大学",] ggplot(rbind(tsinghua,xmu),aes(rank,fill=university)) + geom_density(color="transparent",alpha=0.5) + labs(x="名次",y="密度",title="两个学校名次分布对比\n") + facet_grid(university~.) |
两个学校的整体实力很容易就能看出来了。清华大学的队大部分集中在前500名,表现较好。
另外还想到的就是可能可以利用ROC曲线来衡量一个学校的整体表现。关于ROC的具体介绍,可以看这里。继续以清华为例子,画出它的ROC曲线。
1 |
library(ROCR) |
?
1 2 3 4 5 6 7 8 9 10 11 |
probs <- seq(1,0,length.out=nrow(leaderBoard)) labels <- rep(0,nrow(leaderBoard)) labels[tsinghua$rank] = 1 pred <- prediction(probs ,labels) perf <- performance(pred,"tpr","fpr") perf <- data.frame(FPR = [email protected][[1]], TPR = [email protected][[1]]) ggplot(perf, aes(FPR,TPR)) + labs(title="ROC Curve\n") + geom_density(stat="identity", fill="steelblue", color="transparent",alpha=0.6) |
这个ROC曲线下的面积成为AUC (area under curve),该部分面积越大,代表整体排名越前。可以利用ROCR包很容易的计算出AUC:
1 |
performance(pred,"auc")@y.values[[1]] |
?
1 |
## [1] 0.6233 |
AUC的值超过0.5,说明该校整体表现高于平均水准;小于0.5,说明整体表现低于平均水准。
写一个function来计算所有学校的AUC:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
auc <- function(ranks, n) { probs <- seq(1, 0, length.out = n) labels <- rep(0, n) labels[ranks] <- 1 pred <- prediction(probs, labels) perf <- performance(pred, "auc") [email protected][[1]] } auc_leaderboard <- ddply(leaderBoard, .(university), function(x) { c(auc = auc(x$rank, nrow(leaderBoard)), num_teams = nrow(x)) }) auc_leaderboard <- auc_leaderboard[order(auc_leaderboard$auc, decreasing = T), ] auc_leaderboard <- auc_leaderboard[auc_leaderboard$num_teams >= 8, ] rownames(auc_leaderboard) <- 1:nrow(auc_leaderboard) auc_leaderboard |
根据AUC排序的榜单
? |
university |
auc |
num_teams |
1 |
西南交通大学 |
0.7116 |
11 |
2 |
华中师范大学 |
0.7084 |
10 |
3 |
中国人民大学 |
0.6417 |
9 |
4 |
清华大学 |
0.6233 |
37 |
5 |
香港科技大学 |
0.6228 |
15 |
6 |
北京航空航天大学 |
0.6092 |
22 |
7 |
东北大学 |
0.6062 |
17 |
8 |
华东师范大学 |
0.5975 |
14 |
9 |
中国科学技术大学 |
0.5848 |
47 |
10 |
北京大学 |
0.5785 |
39 |
11 |
武汉大学 |
0.5680 |
19 |
12 |
北京理工大学 |
0.5594 |
25 |
13 |
北京邮电大学 |
0.5489 |
87 |
14 |
浙江大学 |
0.5391 |
97 |
15 |
西北工业大学 |
0.5118 |
8 |
16 |
哈尔滨工业大学 |
0.5106 |
45 |
17 |
广东工业大学 |
0.5073 |
8 |
18 |
上海交通大学 |
0.5047 |
20 |
19 |
大连理工大学 |
0.5006 |
19 |
20 |
南京大学 |
0.4901 |
40 |
21 |
同济大学 |
0.4881 |
15 |
22 |
厦门大学 |
0.4865 |
15 |
23 |
南开大学 |
0.4817 |
11 |
24 |
电子科技大学 |
0.4809 |
56 |
25 |
东南大学 |
0.4769 |
27 |
26 |
中国科学院大学 |
0.4751 |
76 |
27 |
中山大学 |
0.4747 |
35 |
28 |
南京邮电大学 |
0.4724 |
8 |
29 |
天津大学 |
0.4632 |
12 |
30 |
山东大学 |
0.4617 |
14 |
31 |
东华大学 |
0.4585 |
11 |
32 |
西安交通大学 |
0.4277 |
12 |
33 |
复旦大学 |
0.4062 |
25 |
34 |
西安电子科技大学 |
0.4049 |
37 |
35 |
华南理工大学 |
0.4048 |
28 |
36 |
华中科技大学 |
0.3995 |
35 |
上面的学校排名有更符合您心目中的预期吗?