去年比赛的时候初赛做到第6名。换数据之前是第4名。
首先我们先看一下评估指标
评估指标
我们希望参赛队对于每一条博文预测出发表一周后的转发数、评论数和赞的数目,对于每一项均和真实值计算偏差:
注:countfp为预测的转发数,countfr为实际的转发数;countcp为预测的评论数,countcr为实际的评论数 countlp为预测的赞数, countlr为实际的赞数
结合上述三项偏差,计算第i篇博文的准确率:
最后,计算整体的准确率
其中:sgn(x)为改进的符号函数,当x>0时,sgn(x)=1当x<=0时,sgnx(x)=0
counti为第i篇博文的总的转发、评论、赞之和,当counti>100时,取值为100
对于一个不懂自然语言处理 的人来说仿佛这个不太好下手啊,第一感觉仿佛是要用回归或者分类,因为是预测的具体数值
所以前期就疯狂提特征,结果尼玛发现自己太菜了,特征没啥卵用啊。
后来又看到大家都在使用均值模型,也就是俗称看脸大法
看脸大法好啊,每个用户都预测一样的值
那么问题来了,这个值该预测为多大呢?
有人说均值,有人说全0,有人说中位数
那么我们再看下评分公式,我们可否利用这个公式来得到一个最优值,让这个值对这个用户预测的得分最大?
不说数学,我也不懂数学,我懂蛮力法。
那么我们用蛮力法是否能解决呢
也就是我们从用3个for循环,让转赞评 从最小值到最大值循环,对每个用户保留得分最大的值。
这样的话开多线程大概几个小时就能跑完
简直不能忍,能否有更简单的办法呢?
那就是直接一个for循环,你们肯定会说仿佛在逗我笑
我没开玩笑
用户的记录都是转赞评在一起的,那么我们直接把用户的历史记录一条一条的带进去算一个能让得分最大的历史记录
也就是说得到的值就是用户历史记录里面的
这样1分钟不到搞定,简单山寨可依赖。
当然还有些预处理和优化,该动动脑筋啦
下面的代码直接运行可以做到30.05%的样子,是不是很easy~
另外3个值直接从min~max循环的话就能做到我初赛的成绩31.39%
按照复赛的ppt来实现的话估计就能干掉新人挑战赛第一名啦
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
public class Model {
public static void main(String[] args) throws Exception {
HashMap<String, ArrayList<String>> map=new HashMap<>();
String line="";
//读入训练数据
BufferedReader br=readFile("H:\\Competition\\weibo\\Weibo Data\\weibo_train_data.txt");
while((line=br.readLine())!=null){
String uid=line.split("\t")[0];
String fcl=line.split("\t")[3]+","+line.split("\t")[4]+","+line.split("\t")[5];
//按用户分组保存
if (map.containsKey(uid)) {
map.get(uid).add(fcl);
}else{
ArrayList<String> list=new ArrayList<>();
list.add(fcl);
map.put(uid, list);
}
}
//拟合每一个用户
HashMap<String, String> answer=new HashMap<>();
for(String uid:map.keySet()){
answer.put(uid, fit(map.get(uid)));
}
//读入预测数据
br=readFile("H:\\Competition\\weibo\\Weibo Data\\weibo_predict_data.txt");
PrintWriter pt=writeFile("H:\\Competition\\weibo\\Weibo Data\\weibo_result_data.csv");
//直接抄答案
while((line=br.readLine())!=null){
String temp[]=line.split("\t");
String uid=temp[0];
String mid=temp[1];
String predict=answer.get(uid)==null?"0,0,0":answer.get(uid);
pt.println(uid+"\t"+mid+"\t"+predict);
}
pt.close();
br.close();
}
public static String fit(ArrayList<String> list) {
HashSet<String> set = new HashSet<>();
int n = 0;
while (n < list.size()) {
set.add(list.get(n));
n++;
}
double max_precision = 0;
int best_f = 0, best_c = 0, best_l = 0;
for (String line_ : set) {
double sum_denom = 0;// 分母
double sum_number = 0;// 分子
int i = Integer.parseInt(line_.split(",")[0]);
int j = Integer.parseInt(line_.split(",")[1]);
int k = Integer.parseInt(line_.split(",")[2]);
for (String line : list) {
String trueStr[] = line.split(",");
int fr = Integer.parseInt(trueStr[0]);
int cr = Integer.parseInt(trueStr[1]);
int lr = Integer.parseInt(trueStr[2]);
double df = Math.abs(i - fr) / (fr + 5.0);
double dc = Math.abs(j - cr) / (cr + 3.0);
double dl = Math.abs(k - lr) / (lr + 3.0);
double precision_i = 1 - 0.5 * df - 0.25 * dc - 0.25 * dl;
double count_i = fr + cr + lr;
if (count_i > 100)
count_i = 100;
double sgnValue_i = 0.0;
if (precision_i > 0.8)
sgnValue_i = 1;
sum_denom += count_i + 1;
sum_number += (count_i + 1) * sgnValue_i;
}
if (sum_number / sum_denom > max_precision) {
max_precision = sum_number / sum_denom;
best_f = i;
best_c = j;
best_l = k;
}
}
return best_f + "," + best_c + "," + best_l;
}
public static BufferedReader readFile(String src) throws Exception {
// return new BufferedReader(new FileReader(new File(src)));
return new BufferedReader(new InputStreamReader(new FileInputStream(new File(src)), "UTF-8"));
}
public static PrintWriter writeFile(String dst) throws Exception {
return new PrintWriter(new FileWriter(dst));
}
}