正式赛已经开始几天了,但这几天有很多事要忙,所以每什么时间来做比赛,昨天把数据下下来,结合论坛里某个小伙伴的baseline简单分析了下数据。把一些自己的分析记录在下面,供大家参考,同时能有所启发得到一些解题的思路。 baseline看过后基本上可以把整个数据处理流程和提交理清楚了,这里对里面的一些代码进行了一些小小的修改,在保证结果一致的情况下,改进了些,加快运算速度。(一般在提取特征的时候,我们尽量少用apply,因为它是逐条对数据处理,而应该多用矩阵运算来代替,能少用merge操作尽量少用,因为它需要匹配标识符,这点我们可以通过sort保持顺序,groupby之后的顺序是对应的就可以避免merge) 当然还有很多,比如groupby聚合之后,id的顺序和之前的顺序是保持一致的,有时候能减少Merge的操作。一些小技巧,在代码优化方面可以加速特征运算的效率,毕竟数据量有那么大,代码优化方面还是有必要的。 trian里面的数据太大了,先放一边,我们先看看test里面有哪些东西。 总共有87艘船 上面这段输出可以基本上了解test中的一些信息了,小伙伴自行read,就不多废话了。 这个比赛最重要的信息就是gps经纬度坐标,我们先着重分析下。通过查询test中的经纬度范围,经度一般在-180~180之间,基本上是横跨了这个世界地图(华为业务遍布全球 哈哈),纬度范围是-50到50 ,可以确定是在赤道附近(毕竟海路运输都是在赤道附近)。这里对于经纬度不是很熟悉的小伙伴可以百度了解下,我也是今天才补的知识 ~ ~。 有了经纬度我们就可以计算距离了,但是计算距离也是个比较麻烦的事情,我们要转换为欧式距离才好有个清晰的距离概念。这里我给除了计算公式: 哈哈 即使知道公式也还是有点蒙,对吧! 好的!! 接下来我们具体吧一个运单根据经纬坐标画出来看看是怎样的: 这里在补几张图,我在trian数据里面画了几张相同trace路线的loadingOder的终点,可以看出,虽然路线是一样的,但是不同的运输单终点还是有一定差距的(终点并不是很聚合) 从上面的分析我们对数据有了一些了解,对于训练数据需要考虑的问题也在上面说了。由于train数据太大,几乎不可能一次性读取,所以只能选择批量读取,同时从里面抽取我们需要的数据保存下来。pandas批量读取只要在read_csv中设置chunksize的大小就可以了,这里放上示例,小伙伴们可以自由发挥: #———————————————-我是分割线!!!—————————————————–
2020中国高校计算机大赛·华为云大数据挑战赛–数据分析(一)
首先这里放上baseline的链接,感谢姜大德的,提供了一份完整的从载入数据,处理数据到训练模型和提交的完整步骤!
basline链接一、baseline
这里举个小例子,提供参考,这里是对anchor计算的部分,我改写成下面这段代码:def get_anchor(df): tmp=df.groupby('loadingOrder') df['lat_diff'] = tmp['latitude'].diff(1) df['lon_diff'] = tmp['longitude'].diff(1) df['speed_diff'] = tmp['speed'].diff(1) df['diff_minutes'] = tmp['timestamp'].diff(1).dt.total_seconds() // 60 ###直接用numpy的与运算,比apply中if判断要快的多 df['anchor'] =((df['lat_diff']<= 0.03)&(df['lon_diff'] <= 0.03)&(df['speed_diff'] <= 0.3)&(df['diff_minutes'] <= 10)).astype('int') ### 这里标记下船几乎停止的地方 df['stop']=((df['lat_diff'] <= 0.03)&(df['lon_diff'] <= 0.03)&(df['speed'] <= 1)).astype('int') # return df
tmp= group['timestamp'].agg({'mmax':'max','mmin':'min'}).reset_index(drop=True) # 读取数据的最大值-最小值,即确认时间间隔 group_df['time_gap'] = (tmp['mmax'] - tmp['mmin']).dt.total_seconds()
二、测试数据分析
test_df=pd.read_csv('./A_testData0531.csv') print('总共有{}艘船'.format(test_df.vesselMMSI.nunique())) print('{}个快递运单'.format(test_df.loadingOrder.nunique())) print('{}个运货公司'.format(test_df.carrierName.nunique())) print('{}条运输路径'.format(test_df.TRANSPORT_TRACE.nunique())) print('运输路段长度:{}'.format(test_df.TRANSPORT_TRACE.apply(lambda x:len(x.split('-'))).unique())) print('运输过程中的 spped 情况:{}'.format(test_df.speed.unique())) print('经度跨越:{}'.format(test_df.longitude.max()-test_df.longitude.min()),'纬度跨越:{}'.format(test_df.latitude.max()-test_df.latitude.min())) print('测试集中,船只的运输的港口:') print(test_df.TRANSPORT_TRACE.value_counts()) print('测试集时间跨度:') print('min time:{} max time:{}'.format(test_df.timestamp.min(),test_df.timestamp.max()))
222个快递运单
8个运货公司
22条运输路径
运输路段长度:[2]
运输过程中的 spped 情况:[31 30 29 28 32 33 35 34 15 13 11 23 24 26 27 37 36 0 25 14 16 12 8 10
17 18 19 20 9 7 6 5 3 21 22 1 2 40 42 43 41 39 38 4 44 46 47 50
49]
经度跨越:359.046092 纬度跨越:85.676263
测试集中,船只的运输的港口:
CNYTN-MXZLO 25685
CNYTN-PAONX 5700
CNSHK-CLVAP 2900
CNYTN-ARENA 2833
CNSHK-MYTPP 1855
CNYTN-MATNG 1694
CNSHK-GRPIR 721
CNYTN-CAVAN 657
CNHKG-MXZLO 613
CNSHK-SGSIN 595
CNYTN-RTM 357
CNSHA-SGSIN 292
CNSHK-SIKOP 266
COBUN-HKHKG 245
HKHKG-FRFOS 223
CNYTN-NZAKL 165
CNSHK-ZADUR 150
CNSHK-ESALG 150
CNSHA-PAMIT 113
CNSHK-PKQCT 104
CNYTN-MTMLA 69
CNSHK-LBBEY 69
Name: TRANSPORT_TRACE, dtype: int64
测试集时间跨度:
min time:2019-01-10T00:27:58.000Z max time:2020-03-27T00:10:08.000Z
值得注意的是test里面的trace基本都是两段式,但实际可能是不只两个停靠港口的,中间一般可能会有中转港。
从speed上可以看出,船也不是一直在航线,其中停止的时候也是会有gps记录的。另外test中的时间跨度还是非常大的,这其中还包括了疫情期间的时间,疫情对运输应该也有影响,所以时间段也是个很重要的信息。经纬度坐标
纬度分北纬南纬,赤道为分界线。经度分东西,以子午线为0度,+180至-180.C = sin(LatAPi/180)sin(LatBPi/180) + cos(LatAPi/180)cos(LatBPi/180)*cos((MLonA-MLonB)*Pi/180)
Distance = R*Arccos©*Pi/180
没关系,这里我已经写成了python代码,只要直接输入两点的经纬度就可以计算出来距离,单位是m。
参考的是别人java版本写的一个python版本的距离计算公式,需要的小伙伴可以拿去:import numpy as np def distance(LatA,LatB,LonA,LonB): EARTH_RADIUS = 6378.137 # 千米 def rad(d): return d * np.pi/ 180.0 s=0 radLatA = rad(LatA) radLatB = rad(LatB) a = radLatA-radLatB b = rad(LonA)-rad(LonB) s= 2 * np.arcsin(np.sqrt(np.power(np.sin(a / 2),2)+ np.cos(radLatA) * np.cos(radLatB)*np.power(np.sin(b / 2),2))) s=s* EARTH_RADIUS # 保留两位小数 s = np.round(s * 100)/100 s = s * 1000 # 转换成m return s
红色点表示船几乎停止,绿色是起始点,蓝色是重点。
gps数据来看,还是比较规范的,没有特别多的离群点。
但是这样总归不好看,不知道该轨迹的具体位置,下面我们放到世界地图上看看到底是怎样的一条轨迹。
这里选取了一种trace的多个运单,为了对比他们的起始和终止点是否一致!
这张图就可以很明显看到,船从深圳出发,跨国了大洋彼岸,来到了大概像是阿根廷的地方!
我们可以看到,起始点的坐标基本上是一致的,但是终点却不是那么一致,有的在远处就没有了。(注意这里我取的是trian里面的数据,因为train里面才是完整的Gps路由信息,test是截断了的(因为要预测到港时间!不截断还预测什么哈哈!))
所以在构造训练集的时候,我们要充分考虑清楚一下几个问题:
1、船到港的确切时间该如何计算。(肯定会有误差)
2、训练集的构建应该和test一致,test中是截断了的,所以trian中的数据也要人为截断一个完整路由来作为一个训练样本。
3、确定目的港口的gps坐标,或者说是目的停靠点位置(这样我们才能计算出当前段落距离目的地的距离)
…
要考虑的问题还挺多的,从题目来看,做数据清洗,和构造是主要工作,我们应该仔细读题,从赛方给我我们的海量数据中尽可能多的提取有用信息。
下面是相同trace,不同loadingOrder的路劲,也可以看出 终点位置是有差距的,同时每条数据的timestamp并不是等间距的,就也就是位置数据获取的频率是变化的。
总结
import pandas as pd from stqdm import tadm train_flux=pd.read_csv('./train0523.csv',chunksize=10000,names=names) ## 注意 train里面的yundan不是按顺序放好的,所以要读取完整的loadingOrder数据最好从头到尾扫描一遍 count=0 loadingOrders=[] # 可以用来记录读取了多少个loadingOrders train_df=pd.DataFrame(columns=names) for data in tqdm(train_flux): #这部分可以是你对data的处理 train_df.append(data) train_df.head()
这里在放上一个减少内存的代码,输入DataFarme即可,里面小伙伴也可以根据需要自行修改
def reduce_mem_usage(props): # 计算当前内存 start_mem_usg = props.memory_usage().sum() / 1024 ** 2 print("Memory usage of the dataframe is :", start_mem_usg, "MB") # 哪些列包含空值,空值用-999填充。why:因为np.nan当做float处理 NAlist = [] for col in props.columns: # 这里只过滤了objectd格式,如果你的代码中还包含其他类型,请一并过滤 if (props[col].dtypes != object): print("**************************") print("columns: ", col) print("dtype before", props[col].dtype) # 判断是否是int类型 isInt = False mmax = props[col].max() mmin = props[col].min() # # Integer does not support NA, therefore Na needs to be filled # if not np.isfinite(props[col]).all(): # NAlist.append(col) # props[col].fillna(-999, inplace=True) # 用-999填充 # test if column can be converted to an integer asint = props[col].fillna(0).astype(np.int64) result = np.fabs(props[col] - asint) result = result.sum() if result < 0.01: # 绝对误差和小于0.01认为可以转换的,要根据task修改 isInt = True # make interger / unsigned Integer datatypes if isInt: if mmin >= 0: # 最小值大于0,转换成无符号整型 if mmax <= 255: props[col] = props[col].astype(np.uint8) elif mmax <= 65535: props[col] = props[col].astype(np.uint16) elif mmax <= 4294967295: props[col] = props[col].astype(np.uint32) else: props[col] = props[col].astype(np.uint64) else: # 转换成有符号整型 if mmin > np.iinfo(np.int8).min and mmax < np.iinfo(np.int8).max: props[col] = props[col].astype(np.int8) elif mmin > np.iinfo(np.int16).min and mmax < np.iinfo(np.int16).max: props[col] = props[col].astype(np.int16) elif mmin > np.iinfo(np.int32).min and mmax < np.iinfo(np.int32).max: props[col] = props[col].astype(np.int32) elif mmin > np.iinfo(np.int64).min and mmax < np.iinfo(np.int64).max: props[col] = props[col].astype(np.int64) else: # 注意:这里对于float都转换成float16,需要根据你的情况自己更改 props[col] = props[col].astype(np.float16) print("dtype after", props[col].dtype) print("********************************") print("___MEMORY USAGE AFTER COMPLETION:___") mem_usg = props.memory_usage().sum() / 1024**2 print("Memory usage is: ",mem_usg," MB") print("This is ",100*mem_usg/start_mem_usg,"% of the initial size") return props#, NAlist ##示例 train_df=reduce_mem_usage(train_df)
由于时间比较有限,我也只是简单的分析测试了下数据,并没有详细分析,后续如果有好的idel以及建模思路,会继续在Blog上与大家,如果有不对的地方,欢迎大家批评指正。
对了 关于提交文件的格式,赛方说linux下保存会出问题,所以我的解决办法是down到windos本地下,在用pands打开保存下就可以了。然后需要注意的就是timestamp的格式需要和官方的一致才行,这里是baseline里面,我对里面进行了改进,亲测提交有效哦:test_df = test_df.merge(result, on='loadingOrder', how='left') # 这里是放入ETA数据,根据需要可自行改写 test_df['ETA']=(test_df['onboardDate'] + test_df['label'].apply(lambda x:pd.Timedelta(seconds=x))).apply(lambda x:x.strftime('%Y/%m/%d %H:%M:%S')) test_df.drop(['direction','TRANSPORT_TRACE'],axis=1,inplace=True) test_df['onboardDate'] = test_df['onboardDate'].apply(lambda x:x.strftime('%Y/%m/%d %H:%M:%S')) test_df['creatDate'] = pd.datetime.now().strftime('%Y/%m/%d %H:%M:%S') test_df['timestamp'] =test_df['timestamp'].apply(lambda x:x.strftime('%Y-%m-%dT%H:%M:%S.000Z'))# 注意这里的时间格式哦 # 整理columns顺序 result = test_df[['loadingOrder', 'timestamp', 'longitude', 'latitude', 'carrierName', 'vesselMMSI', 'onboardDate', 'ETA', 'creatDate']] # result.to_csv('result.csv',index=False,)
本网页所有视频内容由 imoviebox边看边下-网页视频下载, iurlBox网页地址收藏管理器 下载并得到。
ImovieBox网页视频下载器 下载地址: ImovieBox网页视频下载器-最新版本下载
本文章由: imapbox邮箱云存储,邮箱网盘,ImageBox 图片批量下载器,网页图片批量下载专家,网页图片批量下载器,获取到文章图片,imoviebox网页视频批量下载器,下载视频内容,为您提供.
阅读和此文章类似的: 全球云计算