文章目录
本文主要是学习了天池的智慧海洋建设比赛的一些TOP方案,并对思路进行整理,本文以TOP1的方案为主,其他方案作为补充。
参考的文章如下:
- 2020DCIC智能算法赛-智慧海洋建设TOP1方案
- DCIC 2020数字中国创新大赛数字政府赛道:智慧海洋建设Rank 3解决方案
- 智慧海洋复赛0.89937方案代码开源
- 智慧海洋建设算法赛道B榜top5 方案及源码
- 42个特征+xgboost top7方案-完整notebook
非常感谢前排大佬开源的方案!
数据探索与预处理
渔船作业方式的定义
拖网:拖曳渔具在海底或海水中前进,对鱼类进行捕捞的作业方式。
围网:使用网具包围鱼群进行捕捞的作业方式
刺网:将长带形的网列敷设于水域中,使鱼刺入网目或被网衣缠络后加以捕捞
渔船作业过程中的三种状态
Anchored-off:船舶休息的点
Turning:船舶转弯的点
Straight-sailing:船舶航行的点
预处理
轨迹数据预处理方面, 将平面坐标转换为经纬度坐标。首先采用了经验阈值均值滤波去除了每条轨迹速度的异常值、坐标的离群点, 并用多项式插值函数对离群点进行了插值,基于局部速度对异常坐标点进行插值。
特征工程
统计特征
1,分箱特征,距离海岸线的近似值。
对v求分箱特征,等分为200份,求每一份的统计值
对x求分箱特征,1000份和10000份,求每一份的次数统计值,和每一个分箱对应不同id数目
对y求分箱特征,1000份和10000份,求每一份的次数统计值,和每一个分箱对应不同id数目
求x,y分箱后的组合特征做为分组,求对应的次数统计值,和对应的id的不同数目
根据x分组,求y距离最小y的距离 # 可以理解为距离海岸线距离
根据y分组,求x距离最小x的距离 # 可以理解为距离海岸线距离
2,对渔船的经纬度序列做均值、方差、分位数、众数等统计,可以简单地刻画渔船的活动范围
mode_df = data.groupby(['渔船ID', 'lat', 'lon'])['time'].agg({'mode_cnt':'count'}).reset_index()
mode_df['rank'] = mode_df.groupby('渔船ID')['mode_cnt'].rank(method='first', ascending=False)
for i in range(1, 4):
tmp_df = mode_df[mode_df['rank']==i]
del tmp_df['rank']
tmp_df.columns = ['渔船ID', 'rank{}_mode_lat'.format(i), 'rank{}_mode_lon'.format(i), 'rank{}_mode_cnt'.format(i)]
data_ = data_.merge(tmp_df, on=['渔船ID'], how='left')
3,间隔空间位移特征
根据id分组,对x求,上一个x,下一个x,间隔2个x的距离
根据id分组,对y求,上一个y,下一个y,间隔2个y的距离
根据上述距离,求上一时刻,下一时刻,间隔2个时刻的面积,相对值
4,行程特征
总行程距离
每一步行程的占比
将'dist_move_prev_bin_sen', 'v_bin_sen'转化为onehot稀疏特征
5,其他:
分别计算每个ship中速度大于0小于等于2、大于2小于等于6、大于6小于等于10的比例和平均值,三种区间代表三种运动状态,
以每个区间中的平均速度代表该船在该运动状态下的速度描述(根据速度的分布图选择的对速度的分箱方式)。以速度大于4的连续运动片段作为工作状态,计算每个ship中的工作状态片段并计算每个片段的位移作为作业间隔,统计每个ship中的作业间隔的中位数特征。
利用原数据’time’特征,提取其‘分钟’特征,计算其最大值。
时间差的平均值。时间差的分位数。时间差的中位数。
计算每个ship中角度的平均值。设计了拐角特征,并统计每艘船的三种拐角形式的数量,均值作为特征。
数据处理:skew较大的特征使用log函数将其正态化;与速度相关的特征保留其两位有效数字。
表征渔船的轨迹
POI信息
将每条轨迹投射到网格坐标系下,这样轨迹序列变为了网格id的符号序列; 随后我们基于被boat_id不同的渔船访问次数, 不同boat_id的渔船在该网格停留的平均时长和网格总的被访问的次数三个判据,筛选出了一系列的POI网格。
基于轨迹序列绝对和相对位置的复合向量编码
经纬度常规的统计特征对渔船轨迹信息的表征能力其实是有限的,这里我们设计了一种轨迹序列的编码方式(该方法可拓展至其他类型的轨迹序列数据),进一步刻画了轨迹的动态信息和渔船经过的每个点之间的联系
1,Geohash7编码:Geohash其实是将地图拆分成了一个个矩形网格,当经纬度落入到某个网格内时,则使用网格的编码代替经纬度,这相当于是一种聚类方式。这里我们不直接使用经纬度(细粒度)的好处就是可以提高特征的泛化能力。除此之外,我们还采用了全集和下采样两种提取方式来提取Geohash7编码后的轨迹序列。下采样的好处是缓解渔船位置信息频繁上报而产生的噪音。

2,梯度编码:轨迹序列的梯度是指的后一个位置相对于前一个位置的变化,目的是为了获取相对位置信息

3,基于Word2Vec和Node2Vec的DNN编码:主要思想是将渔船的轨迹序列当成文本,每个地点(Geohash编码)则是一个 “词语”,使用Word2Vec进行向量表征;把渔船经过的地点构造成 “点”,而不同地点之间的关系构造成 “边”,使用Node2Vec进行向量表征。
def w2v_feat(df, group_id, feat, length):
print('start word2vec ...')
data_frame = df.groupby(group_id)[feat].agg(list).reset_index()
model = Word2Vec(data_frame[feat].values, size=length, window=5, min_count=1, sg=1, hs=1,
workers=1, iter=10, seed=1, hashfxn=hashfxn)
# data_frame[feat] 存放每个渔船的[xz5k92v, xz5k99f, ...,xz5kdjj]对应的【二维表】,维度:(n , 30)
# n 是渔船的所有轨迹记录[xz5k92v, xz5k99f, ...,xz5kdjj]的个数
# 30是每个轨迹数据,如xz5k92v,通过Word2Vec得到是30维向量
# 即每一行都存放了一个轨迹记录的30维向量
data_frame[feat] = data_frame[feat].apply(lambda x: pd.DataFrame([model[c] for c in x]))
# 遍历30维向量的每个分量
for m in range(length):
# 计算n行30维向量 的 每个分量 的均值,也就是计算第m列均值,作为该渔船的一个Word2Vec特征。
data_frame['w2v_{}_mean'.format(m)] = data_frame[feat].apply(lambda x: x[m].mean())
del data_frame[feat]
return data_frame
4,TFIDF&CountVec编码:
此类编码方式也是借鉴了文本的常用处理方法,提取渔船轨迹序列中Geohash的频次信息。
def tfidf(input_values, output_num, output_prefix, seed=1024):
tfidf_enc = TfidfVectorizer()
tfidf_vec = tfidf_enc.fit_transform(input_values)
svd_tmp = TruncatedSVD(n_components=output_num, n_iter=20, random_state=seed)
svd_tmp = svd_tmp.fit_transform(tfidf_vec)
svd_tmp = pd.DataFrame(svd_tmp)
svd_tmp.columns = ['{}_tfidf_{}'.format(output_prefix, i) for i in range(output_num)]
return svd_tmp
表征渔船不同状态下的信息
Anchored-off状态特征
认为当渔船的速度为0时,渔船处于停靠或是收网的状态。统计该状态下渔船所处的位置,可以让模型捕捉到不同作业方式下渔船停靠点或收网点的规律。
for col in ['lat', 'lon']:
print(col)
group_df = data[data['速度']==0].groupby(['渔船ID'])[col].agg(
{'锚点_'+col+'_mean': 'mean',
'锚点_'+col+'_max': 'max',
'锚点_'+col+'_min': 'min',
'锚点_'+col+'_nuniq': 'nunique',
'锚点_'+col+'_q1': lambda x: np.quantile(x, 0.10),
'锚点_'+col+'_q2': lambda x: np.quantile(x, 0.20),
'锚点_'+col+'_q3': lambda x: np.quantile(x, 0.30),
'锚点_'+col+'_q4': lambda x: np.quantile(x, 0.40),
'锚点_'+col+'_q5': lambda x: np.quantile(x, 0.50),
'锚点_'+col+'_q6': lambda x: np.quantile(x, 0.60),
'锚点_'+col+'_q7': lambda x: np.quantile(x, 0.70),
'锚点_'+col+'_q8': lambda x: np.quantile(x, 0.80),
'锚点_'+col+'_q9': lambda x: np.quantile(x, 0.90)}
).reset_index()
features = features.merge(group_df, on=['渔船ID'], how='left')
Turning状态特征
将数值型的方向特征进行离散化处理后,统计渔船作业过程中不同方向的频次及比例。
data['方向'] = data['方向'].apply(lambda x:(int(round(x/30)))*30)
degree_df = data.pivot_table(index='渔船ID',columns='方向',values='lat', dropna=False, aggfunc='count').fillna(0)
degree_df.columns = [str(f)+'_方向_count' for f in degree_df.columns]
degree_df.reset_index(inplace=True)
Straight-sailing状态特征
渔船的历史数据中存在大量的速度为0的记录,会对速度进行均值、方差等统计产生较大的影响。我们单独取速度大于0时的样本,再对速度构造统计特征,一方面去除速度为0的影响、另一方面刻画了渔船航行时的状态。
group_df = data[data['速度']>0].groupby(['渔船ID'])['速度'].agg({
'速度_mean_new': 'mean',
'速度_q10_new': lambda x: np.quantile(x, 0.10),
'速度_q20_new': lambda x: np.quantile(x, 0.20),
'速度_q30_new': lambda x: np.quantile(x, 0.30),
'速度_q40_new': lambda x: np.quantile(x, 0.40),
'速度_q50_new': lambda x: np.quantile(x, 0.50),
'速度_q60_new': lambda x: np.quantile(x, 0.60),
'速度_q70_new': lambda x: np.quantile(x, 0.70),
'速度_q80_new': lambda x: np.quantile(x, 0.80),
'速度_q90_new': lambda x: np.quantile(x, 0.90),
}).reset_index()
动态信息特征
每个渔船id的速度、经纬度看做是一个序列信息
利用速度、经纬度的分位数统计量,将浮点特征分桶转成一个类型特征
使用不同的ngram提取TF-IDF 特征(ngram=1, 2, 3)
最终,利用NLP的TF-IDF提取关键高维的ngram信息,有效获取速度和经纬度动态变化的信息
模型策略
五折验证,使用的lightgbm参数如下:
params = {
'learning_rate': 0.05,
'boosting_type': 'gbdt',
'objective': 'multiclass',
'metric': 'None',
'num_leaves': 63,
'feature_fraction': 0.8,
'bagging_fraction': 0.8,
'bagging_freq': 5,
'seed': 1,
'bagging_seed': 1,
'feature_fraction_seed': 7,
'min_data_in_leaf': 20,
'num_class': n_class,
'nthread': 8,
'verbose': -1,
}
再次感谢前排大佬开源的方案!
本文分析了智慧海洋建设中渔船作业方式,包括拖网、围网和刺网,以及渔船的Anchored-off、Turning、Straight-sailing三种状态。通过数据预处理、统计特征提取,如距离海岸线的近似值、轨迹位移特征和时间差统计,结合Geohash编码、Word2Vec和Node2Vec等方法表征轨迹信息。模型策略采用LightGBM,利用五折验证进行训练。
301

被折叠的 条评论
为什么被折叠?



