文章目录

  • 赛题
    • 要求
    • 数据
  • TOP1 解决方案
    • 数据读取
    • 特征工程
    • 基本预处理
    • 统计特征
    • 基于轨迹序列绝对和相对位置的复合向量编码
    • Word2Vec

比赛来源:天池平台 智慧海洋建设

感谢大佬开源TOP1方案: 智慧海洋建设TOP1

本博客只是单纯的对TOP1方案进行整理学习。

赛题

要求

本赛题基于位置数据对海上目标进行智能识别和作业行为分析,要求选手通过分析渔船北斗设备位置数据,得出该船的生产作业行为,具体判断出是拖网作业、围网作业还是流刺网作业。

数据

每艘渔船对应一个csv文件,训练集一共提供11000条渔船北斗数据。

每个csv文件由若干条以下数据组成,刻画了渔船在不同时刻的运动状态。

TOP1 解决方案

导入相关依赖:

import pandas as pd
import numpy as numpy
from tqdm import tqdm
from pyproj import Proj
from sklearn.metrics import classification_report, f1_score
from sklearn.model_selection import StratifiedKFold, KFold
from sklearn.decomposition import TruncatedSVD
from sklearn.feature_extraction.text import TfidfVectorizer,CountVectorizer
from gensim.models import Word2Vec
from gensim.models.doc2vec import Doc2Vec, TaggedDocument
import lightgbm as lgb
import os

数据读取

利用文件读取的方式,对数据读取,将多表数据整合到一张表中。将所有的训练测试数据预测数据保存到一个dataFrame中,便于后续的特征工程。

TRAIN_PATH = '../input/hy_round1_train_20200102'
TEST_PATH =  '../input/hy_round1_testA_20200102'def get_data(file_path,model):file_path = file_pathpaths = os.listdir(file_path)  # 得到file_path目录下的文件名,存入数组paths中tmp = []for t in tqdm(range(len(paths))):p = paths[t]with open('{}/{}'.format(file_path,p),encoding='utf-8') as f:next(f)for line in f.readlines():# strip()去除字符串的头和尾的空格,并以,切割字符串,每一行数据形成一个字符数组。将字符数组添加到tmp数组中。tmp.append(line.strip().split(','))tmp_df = pd.DataFrame(tmp)print(tmp_df.head())if model == 'train':tmp_df.columns = ['ID', 'lat', 'lon', 'speed', 'direction', 'time', 'type']else:tmp_df['type'] = 'unknown'tmp_df.columns = ['ID', 'lat', 'lon', 'speed', 'direction', 'time', 'type']tmp_df['lat'] = tmp_df['lat'].astype(float)tmp_df['lon'] = tmp_df['lon'].astype(float)tmp_df['speed'] = tmp_df['speed'].astype(float)tmp_df['direction'] = tmp_df['direction'].astype(int)return tmp_df# 调用函数,读取并整合数据
train = get_data(TRAIN_PATH,'train')
test = get_data(TEST_PATH,'test')
train = train.append(test)

将原始数据的x,y转为经纬度。

# 将原始数据得x,y 转为经纬度。
def transform_xy2lonlat(df):x = df['lat'].valuesy = df['lon'].valuesp = Proj("+proj=tmerc +lat_0=0 +lon_0=120 +k=1 +x_0=500000 +y_0=0 +a=6378140 +b=6356755.288157528 +units=m +no_defs")df['lon'], df['lat'] = p(x, y, inverse=True)return df
train = transform_xy2lonlat(train)
df = train.copy()

到这里数据读取结束。所有的训练集测试集都保存在表df中。

数据长这样:


每个ID都有若干条记录。type=unknown的表示测试集。

特征工程

基本预处理


# 根据ID和time进行排序
df.sort_values(['ID','time'],inplace=True)
# 将时间处理成 2019-11-10 11:38:19的形式,并转成pandas时间格式
# df['time'] = df['time'].apply(lambda x: '2019-'+ x.split(' ')[0][:2]+ '-'+x.split(' ')[0][2:]+' '+x.split(' ')[1])
df['time'] = df['time'].apply(lambda x: '2019-' + x.split(' ')[0][:2] + '-' + x.split(' ')[0][2:] + ' ' + x.split(' ')[1])
df['time']=pd.to_datetime(df['time'])# 求每艘船的经度 维度 速度 时间的 差分
df['lat_diff'] = df.groupby('ID')['lat'].diff(1)
df['lon_diff'] = df.groupby('ID')['lon'].diff(1)
df['speed_diff'] = df.groupby('ID')['speed'].diff(1)
df['diff_minutes'] = df.groupby('ID')['time'].diff(1).dt.seconds //60# 每艘船是否满足:在10s时间内,经纬度变化量<0.01, 速度<0.1, 如果满足则该船是在锚点处,即停止。
# 使用apply 实现, axis=1表示将函数应用与每一行
df['anchor'] = df.apply(lambda x: 1 if x['lat_diff']<0.01 and x['lon_diff']<0.01 and x['speed']<0.1 and x['diff_minutes'] <=10 else 0,axis=1)# 处理标签 将标签匹配成数字类别如围网对应0,使用map函数实现
df['type'] = df['type'].map({'围网':0, '刺网':1, '拖网':2, 'unknown':-1})

生成group_df 用于保存后续所有特征工程生成的结果。

# 生成group_df,每个ID对应的label,以及每个ID出现的总次数
# mean的结果代价label,count等价于每个ID的数据的记录数。
group_df = df.groupby('ID')['type'].agg({'label': 'mean', 'cnt':'count'}).reset_index()

统计特征

1、每艘船的停船率。

# 获取锚点位置信息,先对ID进行分组,每个ID的anchor求和,求出每艘船的锚点位置个数
#  使用groupby+agg组合,分组聚合。返回dataframe
anchor_df = df.groupby('ID')['anchor'].agg('sum').reset_index()
anchor_df.columns = ['ID','anchor_cnt']#将锚点位置信息合并group_df, 求出每艘船的停止率。停止次数/总次数。
group_df = group_df.merge(anchor_df, on='ID', how='left')
group_df['anchor_ratio']= group_df['anchor_cnt'] / group_df['cnt']

2、分别对每个ID的:

(1)所有航行记录的所有数据,

(2)所有数据中经纬度变化量不等于0的数据

(3)所有数据中速度不为0的数据

的’lat’, ‘lon’, ‘speed’, 'direction’特征,求统计量:‘min’, ‘max’, ‘mean’, ‘median’, ‘nunique’, q10, q20, q30, q40, q60, q70, q80, q90。

先取出df中经纬度变化量不等于0的数据lat_lon_neq_zero,取出速度变化量不等于0的数据speed_neg_zero

lat_lon_neq_zero = df[(df['lat_diff']!=0)&(df['lon_diff']!=0)]
speed_neq_zero = df[df['speed_diff']!=0]   

定义函数,获取相应的分位点:

# 定义一些函数,返回数据的分位点数据
def q10(x):return x.quantile(0.1)def q20(x):return x.quantile(0.2)def q30(x):return x.quantile(0.3)def q40(x):return x.quantile(0.4)def q60(x):return x.quantile(0.6)def q70(x):return x.quantile(0.7)def q80(x):return x.quantile(0.8)def q90(x):return x.quantile(0.9)

利用groupby+agg 组合计算相应的统计特征:

stat_functions = ['min', 'max', 'mean', 'median', 'nunique', q10, q20, q30, q40, q60, q70, q80, q90]
stat_ways = ['min', 'max', 'mean', 'median', 'nunique', 'q_10', 'q_20', 'q_30', 'q_40', 'q_60', 'q_70', 'q_80', 'q_90']
stat_cols = ['lat', 'lon', 'speed', 'direction']# 所有数据'lat', 'lon', 'speed', 'direction'统计特征
group_tmp = df.groupby('ID')[stat_cols].agg(stat_functions).reset_index()
group_tmp.columns = ['ID'] + ['{}_{}'.format(i,j) for i in stat_cols for j in stat_ways] #经纬度变化量不等于0的数据的'lat', 'lon', 'speed', 'direction'的统计特征
lat_lon_neq_group = lat_lon_neq_zero.groupby('ID')[stat_cols].agg(stat_functions).reset_index()
lat_lon_neq_group.columns = ['ID'] + ['pos_neq_zero_{}_{}'.format(i, j) for i in stat_cols for j in stat_ways]# 速度不为0的数据'lat', 'lon', 'speed', 'direction'的统计特征
speed_neq_zero_group = speed_neq_zero.groupby('ID')[stat_cols].agg(stat_functions).reset_index()
speed_neq_zero_group.columns = ['ID']+ ['speed_neq_zero_group_{}_{}'.format(i,j) for i in stat_cols for j in stat_ways]# 将这些统计特征合并到group_df中
group_df = group_df.merge(group_tmp, on='ID', how='left')
group_df = group_df.merge(lat_lon_neq_group, on='ID', how='left')
group_df = group_df.merge(speed_neq_zero_group, on='ID', how='left')

3、获取TOP频次位置信息

对时有出现的位置信息(经纬度)进行计数,得到出现次数排名前三的位置。

# 计算位置出现的次数
mode_df = df.groupby(['ID','lat','lon'])['time'].agg({'mode_cut': 'count'}).reset_index()
# 对ID分组,根据mode_cut进行排序
mode_df['rank'] = mode_df.groupby('ID')['mode_cut'].rank(method='first',ascending=False)
# 循环取出出现次数排名前三个的位置,并将其合并到group_df中
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)]group_df = group_df.merge(tmp_df,on='ID',how='left')

到此,统计信息计算结束,group_df维度为170。

接下来的特征工程是这个比赛的TOP1的创新之处。

基于轨迹序列绝对和相对位置的复合向量编码

将 文本化的经纬度和文本化的经纬度梯度 生成词频矩阵,进行LSA降维,降维后30维。

先定义下面三个工具函数:

(1)geohash_encode将经纬度坐标转换成字符串相近的位置字符串相同。

def geohash_encode(latitude, longitude, precision=12):"""Encode a position given in float arguments latitude, longitude toa geohash which will have the character count precision."""lat_interval, lon_interval = (-90.0, 90.0), (-180.0, 180.0)base32 = '0123456789bcdefghjkmnpqrstuvwxyz'geohash = []bits = [16, 8, 4, 2, 1]bit = 0ch = 0even = Truewhile len(geohash) < precision:if even:mid = (lon_interval[0] + lon_interval[1]) / 2if longitude > mid:ch |= bits[bit]lon_interval = (mid, lon_interval[1])else:lon_interval = (lon_interval[0], mid)else:mid = (lat_interval[0] + lat_interval[1]) / 2if latitude > mid:ch |= bits[bit]lat_interval = (mid, lat_interval[1])else:lat_interval = (lat_interval[0], mid)even = not evenif bit < 4:bit += 1else:geohash += base32[ch]bit = 0ch = 0return ''.join(geohash)

(2)tfidf对文本进行tfidf词频特征 ,并利用LSA进行潜在语义分析,也可以理解为用svd降维。每个文本生成output_num维度的向量。

def tfidf(input_values, output_num, output_prefix, seed=1024):# 生成文本Tfidf矩阵,使用TF-IDF对文本进行预处理,将文本化为向量的表示形式,shape=(文本数,词汇数)tfidf_enc = TfidfVectorizer()tfidf_vec = tfidf_enc.fit_transform(input_values)# print('所有文本的关键字',tfidf_enc.get_feature_names())# print('词频矩阵的结果',tfidf_vec.toarray())# 对shape=(文本数,词汇数)的矩阵进行降维,#生成Matrix(文本数,主题数)xMatrix(文本数,主题数),主题数远小于词汇数# truncatedSVD作用于sklearn.feature_extraction.text向量化后返回的 term count/tf-idf矩阵。在这种情况下又被成为LSA( latent semantic analysis)# LSA潜在语义分析,生成主题数为30维,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

(3)count2vec与tfidf功能相似,没有使用tfidf进行词频统计,直接使用计数对词频统计。

def count2vec(input_values, output_num, output_prefix, seed=1024):# CountVectorizer是通过fit_transform函数将文本中的词语转换为词频矩阵# 生成文本词频矩阵count_enc = CountVectorizer()count_vec = count_enc.fit_transform(input_values)# truncatedSVD作用于sklearn.feature_extraction.text向量化后返回的 term count/tf-idf矩阵。在这种情况下又被成为LSA( latent semantic analysis)# LSA潜在语义分析,生成主题数为30维,svd_tmp = TruncatedSVD(n_components=output_num, n_iter=20, random_state=seed)svd_tmp = svd_tmp.fit_transform(count_vec)svd_tmp = pd.DataFrame(svd_tmp)svd_tmp.columns = ['{}_countvec_{}'.format(output_prefix, i) for i in range(output_num)]return svd_tmp

利用gaohash_encode 将每条数据得经纬度转为长度为7得字符串,相近的位置字符串相近


df['lat_lon'] = df.apply(lambda x:geohash_encode(x['lat'], x['lon'], 7), axis=1)# 将每一个ID对应的所有的lat_lon 存到list中,ID [xvkwu60,xvkwu60,xvkwu60,xvkwu60,vkwu60 xvkwu6]
tmp = df.groupby('ID')['lat_lon'].agg(list).reset_index() # agg聚合的结果是一个值(一个分组一个值)。
# list 转字符串 并以空格分隔, ID xvkwu60 xvkwu60 xvkwu60 xvkwu60 xvkwu60 xvkwu6
tmp['lat_lon'] = tmp['lat_lon'].apply(lambda x: ' '.join(x))
print('经纬度文本化的结果:',tmp)

将文本化的经纬度生成的矩阵,进行LSA降维,得到30维特征。

# 将文本化的经纬度生成词向量
tfidf_tmp = tfidf(tmp['lat_lon'], 30, 'lat_lon')
count_tmp = count2vec(tmp['lat_lon'], 30, 'lat_lon')# 合并两个词嵌入的结果,60个特征
tfidf_df = pd.concat([tmp[['ID']],tfidf_tmp,count_tmp],axis=1)# 将这60个特征加入到group_df中
group_df = group_df.merge(tfidf_df,on='ID',how='left')
print('geohash tfidf finished.特征个数',len(group_df.columns))

生成每个ID所有数据经度梯度_维度梯度组合特征

# agg聚合的结果是一个值(一个分组一个值),所以下面代码执行返回一个ID,以及ID对应的lat 的梯度list
# 0  [0.0, 0.0, 3.0, 0.0, 4.0, 0.0, 0.0, 0.0, 0.0, ..
grad_df = df.groupby('ID')['lat'].apply(lambda x: np.gradient(x)).reset_index()
grad_df['lon'] = df.groupby('ID')['lon'].apply(lambda x: np.gradient(x)).reset_index()['lon']
grad_df['lat'] = grad_df['lat'].apply(lambda x: np.round(x, 4))
grad_df['lon'] = grad_df['lon'].apply(lambda x: np.round(x, 4))# 注意下面这行format zip用法,每一时刻的经纬度的梯度会一一匹配。
# 最后结果 -0.0058_0.0034 -0.0058_0.0034 -0.0047_0.0044 -... 经度梯度_维度梯度
grad_df['grad'] = grad_df.apply( lambda x: ' '.join(['{}_{}'.format(z[0],z[1]) for z in zip(x['lat'],x['lon'])]),axis=1)
print(grad_df['grad'])

生成经纬度梯度tfidf矩阵,降维

tfidf_tmp = tfidf(grad_df['grad'], 30, 'grad')
grad_tfidf = pd.concat([grad_df[['ID']], tfidf_tmp], axis=1)
group_df = group_df.merge(grad_tfidf, on='ID', how='left')
print('gradient tfidf finished.')

随机抽取10%的经纬度文本,生成的矩阵,进行LSA降维,得到30维特征。

tmp = df.groupby('ID')['lat_lon'].apply(lambda x: x.sample(frac=0.1, random_state=1)).reset_index()
del tmp['level_1']
tmp.columns = ['ID','sample']
tmp = tmp.groupby('ID')['sample'].agg(list).reset_index()
tmp['sample'] = tmp['sample'].apply(lambda x: ' '.join(x))tfidf_tmp = tfidf(tmp['sample'], 30, 'sample')
sample_tfidf= pd.concat([tmp[['ID']], tfidf_tmp], axis=1)
group_df = group_df.merge(sample_tfidf, on='ID', how='left')
print('sample tfidf finished.')

Word2Vec

将df[‘lat_lon’]的文本作为词库,训练word2vec。

# 训练 word2vec模型
data_frame = df.groupby('ID')['lat_lon'].agg(list).reset_index()
model = Word2Vec(data_frame['lat_lon'].values, size=30, window=5, min_count=1, sg=1, hs=1,workers=1, iter=10, seed=1, hashfxn=hashfxn)# data_frame['lat_lon']中的每一个值,都是一个(n,30)的dataframe,n是指渔船的所有轨迹的个数。
# 30 是指每个轨迹被嵌入到30维。data_frame['lat_lon'] = data_frame['lat_lon'].apply(lambda x: pd.DataFrame([model[c] for c in x]))
# 对每个ID,计算lat_lon的dataframe的30个特征的每一个特征均值,作为最终结果。
for m in range(30):data_frame['w2v_{}_mean'.format(m)] = data_frame['lat_lon'].apply(lambda x: x[m].mean())del data_frame['lat_lon']
w2v_df = data_framegroup_df = group_df.merge(w2v_df, on='ID', how='left')
print('word2vec finished.')

最终生成320个特征。

智慧海洋建设TOP_1方案学习笔记相关推荐

  1. ​DCIC 2020:智慧海洋建设 开源方案复盘笔记

    一.赛题介绍 1.1 赛题背景 本赛题基于位置数据对海上目标进行智能识别和作业行为分析,要求选手通过分析渔船北斗设备位置数据,得出该船的生产作业行为,具体判断出是拖网作业.围网作业还是流刺网作业.初赛 ...

  2. 智慧海洋建设TOP方案借鉴学习与整理

    文章目录 数据探索与预处理 渔船作业方式的定义 渔船作业过程中的三种状态 预处理 特征工程 统计特征 表征渔船的轨迹 POI信息 基于轨迹序列绝对和相对位置的复合向量编码 表征渔船不同状态下的信息 A ...

  3. 2020DCIC智慧海洋建设算法赛学习01-赛题北京及地理数据分析常用工具

    序: 本系列的博客旨在学习2020DCIC智能算法赛-智慧海洋建设的优秀方案,对地理数据分析问题积累一些思路和经验. 作为这一系列博客的开篇,这篇博客主要内容包括对赛题的解析和对项目中会用到的一些常用 ...

  4. 【算法实战篇】时序多分类赛题-2020数字中国创新大赛-智慧海洋建设top5方案(含源码)

        Hi,大家好!这里是AILIGHT!AI light the world!这次给大家带来的是2020数字中国创新大赛-数字政府赛道-智能算法赛:智慧海洋建设的算法赛复赛赛道B top5的方案以 ...

  5. 【时序多分类赛题】2020数字中国创新大赛-智慧海洋建设top5方案(含源码)

       这次给大家带来的是2020数字中国创新大赛-数字政府赛道-智能算法赛:智慧海洋建设的算法赛复赛赛道B top5的方案以及代码开源.比赛传送门:https://tianchi.aliyun.com ...

  6. 【竞赛】智能算法赛:智慧海洋建设Top1方案代码

    海上安全治理是海洋发展中至关重要的环节,了解各个区域船只的工作情况以及具体位置,可以对于防止因为船只的碰撞等事故而造成的巨大损失,而要提升海上安全治理能力,首要任务是"看得清",即 ...

  7. 【比赛实战篇】智能算法赛:智慧海洋建设Top1方案代码

    海上安全治理是海洋发展中至关重要的环节,了解各个区域船只的工作情况以及具体位置,可以对于防止因为船只的碰撞等事故而造成的巨大损失,而要提升海上安全治理能力,首要任务是"看得清",即 ...

  8. 2020DCIC智慧海洋建设算法赛学习02-数据分析

    序: 这篇博客旨在对赛题数据做一些初步的探索,包括查看数据中的缺失值.异常值等,以及通过可视化来观察各个特征的分布情况,为之后进行特征工程提供一些思路. 1. 查看数据整体情况 对于一份数据集,首先要 ...

  9. 【算法竞赛学习】数字中国创新大赛智慧海洋建设-Task4模型建立

    智慧海洋建设-Task4模型建立 此部分为智慧海洋建设竞赛的模型建立模块.在该模块中主要介绍了如何进行模型建立并对模型调优. 学习目标 学习如何选择合适的模型以及如何通过模型来进行特征选择 掌握随机森 ...

最新文章

  1. 干货丨数据科学、机器学习、人工智能,究竟有什么区别?
  2. LINQ to SQL 之DataContext用法
  3. C语言的头文件和库文件(函数库)
  4. java备还原mysql_用java来备份还原mysql数据库
  5. C++对C的加强之变量检测增强
  6. macaca web(4)
  7. C/C++ Memory Layout
  8. 【IBM Tivoli Identity Manager 学习文档】2 部署准备知识
  9. Android应用开发提高系列(5)——Android动态加载(下)——加载已安装APK中的类和资源...
  10. 今天突然出现了Property IsLocked is not available for Login '[sa]',我太阳,下面有绝招对付它!...
  11. javascript异步代码的回调地狱以及JQuery.deferred提供的promise解决方式
  12. openpose学习
  13. Windows打开dcm文件、dcm文件批量转其它图片文件格式
  14. 轻量化网络ShuffleNet MobileNet v1/v2 解析
  15. 族谱程序php,族谱系统
  16. QQ连连看外挂开发过程记录
  17. 如何快速算出一个数的n次方?
  18. 截图快捷键ctrl加什么
  19. office excel 条件格式——使用公式确定要设置格式的单元格——筛选并标记一个表中每行数据的最小(大)值
  20. 使用再生龙镜像备份还原linux,以及遇到的问题和解决方法

热门文章

  1. Ubantu20 OpenAi捉迷藏-Anaconda
  2. 下载Word文档的四种方法
  3. 第一章(6)计算机网络体系结构之计算机网络的性能指标
  4. 【Unreal】未加密的pak文件解包方法
  5. 创建VUE项目,vue-cli2.0版本和3.0版本的区别,将vue2.0项目升级为vue3.0项目
  6. java 星形线代码,JavaScript图形实例:星形条纹图案
  7. uniapp 微信小程序canvas阴影(shadow)在真机上失效,(开发者工具正常)
  8. BPC BPF流程增强BADI
  9. 微通道的兵锋 阿里将血腥
  10. 静电、浪涌与TVS(测试标准、参数、选型)