作者 |Kemal Erdem
编译 |VK
起源 |Towards Data Science
本文基于我在 Driventa 平台上加入 DengAI(登革热)比赛的文章。我的排名在前 0.2%(截至 2020 年 6 月 2 日为 14/9069)。我在这里提出的一些想法是严格为这样的较量设计的,可能在现实生活中不是特地有用。
在开始之前,我必须正告你,对于更高级的数据工程师来说,有些局部可能是不言而喻的,这是一篇十分长的文章。你能够一节一节地读,只需选出你感兴趣的局部。
问题形容
首先,咱们须要探讨比赛自身。DengAI 的指标是(目前是,因为 Driventa 管理局决定将其设为“继续的”较量,因而你能够当初退出)依据天气数据和地点预测特定一周的登革热病例数。
每个参与者都失去了一个训练数据集和测试数据集(不是验证数据集)。MAE(均匀绝对误差)是一种用于计算分数的指标,训练数据集涵盖了 2 个城市(1456 周)28 年的每周的数值。测试数据较小,有逾越 5 年和 3 年的(这取决于城市)。
登革热是一种蚊子流传的疾病,产生在世界寒带和亚热带地区。因为它是由蚊子携带的,该疾病的流传与气象、天气变动无关。
训练数据集:https://github.com/burnpiro/d…
测试数据集:https://github.com/burnpiro/d…
数据集
如果咱们看一下训练数据集,它有多个特色:
城市和日期指标:
- city:sj 代表 San Juan(圣胡安),iq 代表 Iquitos
- week_start_date - 以 yyyy-mm-dd 格局给出的日期
NOAA 的 GHCN 每日气象数据气象站测量:
- station_max_temp_c- 最高温度
- station_min_temp_c- 最低温度
- station_avg_temp_c- 平均温度
- station_precip_mm- 总降水量
- station_diur_temp_rng_c- 昼间温度范畴
卫星降水测量(0.25×0.25 度的标度):
- precipitation_amt_mm- 总降水量
NOAA 的 NCEP 气象预报系统分析测量(0.5×0.5 度的标度):
- reanalysis_sat_precip_amt_mm- 总降水量
- reanalysis_dew_point_temp_k- 均匀露点温度
- reanalysis_air_temp_k- 平均气温
- reanalysis_relative_humidity_percent- 均匀相对湿度
- reanalysis_specific_humidity_g_per_kg- 均匀特定湿度
- reanalysis_precip_amt_kg_per_m2- 总降水量
- reanalysis_max_air_temp_k= 最大空气温度
- reanalysis_min_air_temp_k- 最低空气温度
- reanalysis_avg_temp_k- 平均气温
- reanalysis_tdtr_k- 白天温度范畴
NOAA 的 CDR 归一化差别植被指数(NDVI)(0.5×0.5 度的标度):
- ndvi_se- 城市质心西北的 NVDI
- ndvi_sw- 城市质心东北的 NVDI
- ndvi_ne- 城市质心西南的 NVDI
- ndvi_nw- 城市核心东南的 NVDI
此外,咱们还有每周总病例数的信息。
很容易发现,对于数据集中的每一行,咱们都有多个形容相似数据的特色。有四类:
- 温度
- 降水
- 湿度
- ndvi(这四个特色指的是城市的不同点,因而它们不是完全相同的数据)
因而,咱们应该可能从输出中删除一些冗余数据。
输出示例:
week_start_date 1994-05-07
total_cases 22
station_max_temp_c 33.3
station_avg_temp_c 27.7571428571
station_precip_mm 10.5
station_min_temp_c 22.8
station_diur_temp_rng_c 7.7
precipitation_amt_mm 68.0
reanalysis_sat_precip_amt_mm 68.0
reanalysis_dew_point_temp_k 295.235714286
reanalysis_air_temp_k 298.927142857
reanalysis_relative_humidity_percent 80.3528571429
reanalysis_specific_humidity_g_per_kg 16.6214285714
reanalysis_precip_amt_kg_per_m2 14.1
reanalysis_max_air_temp_k 301.1
reanalysis_min_air_temp_k 297.0
reanalysis_avg_temp_k 299.092857143
reanalysis_tdtr_k 2.67142857143
ndvi_location_1 0.1644143
ndvi_location_2 0.0652
ndvi_location_3 0.1321429
ndvi_location_4 0.08175
提交格局:
city,year,weekofyear,total_cases
sj,1990,18,4
sj,1990,19,5
...
评分评估:
数据分析
在开始设计模型之前,咱们须要查看原始数据并加以修改。为了达到这个目标,咱们将应用 pandas 库。通常,咱们能够间接导入.csv 文件并解决导入的数据帧,但有时(特地是当第一行没有列形容时),咱们必须提供列列表。
import pandas as pd
pd.set_option("display.precision", 2)
df = pd.read_csv('./dengue_features_train_with_out.csv')
df.describe()
Pandas 有一个名为 describe 的内置办法,它显示数据集中列的根本统计信息。
当然,这种办法只实用于数值数据。如果咱们有非数值列,咱们必须先做一些预处理。在咱们的例子中,惟一的列是 city。这个列只蕴含 sj 和 iq 两个值,咱们稍后将解决它。
回到主表。每行蕴含不同类型的信息:
- count - 形容非 NaN 值的个数
- mean - 整列的平均值(用于标准化)
- std - 标准差(也可用于标准化)
- min ->max - 显示蕴含值的范畴(用于缩放)
让咱们从计数开始。晓得数据集中有多少条记录失落了(一个或多个)并决定如何解决这些数据是很重要的。如果你看 ndvi_nw 值,它在 13.3% 的状况下是空的。如果你决定用诸如 0 之类的任意值替换短少的值,这可能是个性能问题。通常,有两种常见的解决方案:
- 设置平均值
- 插值法
插值(解决缺失数据)
当解决序列数据时(就像咱们这个场景一样),从它的邻域中插值(仅从邻域中取平均值)值,而不是用整个汇合中的平均值来代替它,这样比拟正当。
通常,序列数据在序列中的值之间有肯定的相关性,应用邻域能够失去更好的后果。我给你举个例子。
假如你正在解决温度数据,并且你的整个数据集由一月到十二月的值组成。全年的平均值将是一年中大部分工夫缺失天数的有效代替值。
如果从 7 月开始计算,则可能会有[28,27,-,-,30]。如果在伦敦的话,年平均气温是 11 摄氏度(或 52 华氏度)。在这种状况下应用 11 作为温度填充就是谬误的。这就是为什么咱们应该应用插值而不是平均值。
有了插值(即便在有更大差距的状况下),咱们应该可能取得更好的后果。如果你计算这些值,你应该失去(27+30)/2=28.5 和(28.5+30)/2=29.25,所以最终咱们的数据集看起来像是[28,27,28.5,29.25,30],远远好于[28,27,11,11,30]。
将数据集拆分为城市
因为咱们曾经探讨了一些重要的事件,所以咱们能够定义一种办法,该办法容许咱们将分类列(city)从新定义为二进制列向量并对数据进行插值:
def extract_data(train_file_path, columns, categorical_columns=CATEGORICAL_COLUMNS, categories_desc=CATEGORIES,
interpolate=True):
# 读取 csv 文件并返回
all_data = pd.read_csv(train_file_path, usecols=columns)
if categorical_columns is not None:
# 将分类映射到列
for feature_name in categorical_columns:
mapping_dict = {categories_desc[feature_name][i]: categories_desc[feature_name][i] for i in
range(0, len(categories_desc[feature_name]))}
all_data[feature_name] = all_data[feature_name].map(mapping_dict)
# 将映射的分类数据更改为 0 / 1 列
all_data = pd.get_dummies(all_data, prefix='', prefix_sep='')
# 修复失落的数据
if interpolate:
all_data = all_data.interpolate(method='linear', limit_direction='forward')
return all_data
所有常量(如分类列)都在这个要点中定义:https://gist.github.com/burnp…
此函数返回一个数据集,其中蕴含两个名为 sj 和 iq 的二进制列,它们具备布尔值,其中 city 被设置为 sj 或 iq。
绘制数据
绘制数据图以直观地理解值在序列中的散布是很重要的。咱们将应用一个名为 Seaborn 的库来帮忙咱们绘制数据。
sns.pairplot(dataset[["precipitation_amt_mm", "reanalysis_sat_precip_amt_mm", "station_precip_mm"]], diag_kind="kde")
这里咱们只有一个数据集的特色,咱们能够分明地区分节令和城市(平均值从~297 降落到~292)。
另一件有用的事件是不同特色之间的关联。这样咱们就能够从数据集中删除一些冗余的特色。
正如你所留神到的,咱们能够立刻删除其中一个降水特色。一开始这可能是无心的,但因为咱们有来自不同起源的数据,同一类数据(如降水量)并不总是齐全相干的。这可能是因为不同的测量方法或其余起因造成的。
数据相关性
当咱们应用很多特色时,咱们不须要为每一对都绘制成对图。另一个抉择就是计算所谓的相关性分数。不同类型的数据有不同类型的相关性。咱们应用 corr()的办法生成数据集的数值相关性。
如果有不应该被视为二进制的分类列,你能够计算 Cramer 的 V 关联度量来找出它们和其余数据之间的“相关性”。
import pandas as pd
import seaborn as sns
# 导入咱们的提取函数
from helpers import extract_data
from data_info import *
train_data = extract_data(train_file, CSV_COLUMNS)
# 获取“sj”city 的数据并删除两个二进制列
sj_train = train_data[train_data['sj'] == 1].drop(['sj', 'iq'], axis=1)
# 生成热图
corr = sj_train.corr()
mask = np.triu(np.ones_like(corr, dtype=np.bool))
plt.figure(figsize=(20, 10))
ax = sns.heatmap(
corr,
mask=mask,
vmin=-1, vmax=1, center=0,
cmap=sns.diverging_palette(20, 220, n=200),
square=True
)
ax.set_title('Data correlation for city"sj"')
ax.set_xticklabels(ax.get_xticklabels(),
rotation=45,
horizontalalignment='right'
);
你能够对iq 城做同样的事件,并将两者进行比拟(相关性是不同的)。
如果你看看这张热图,很显著能够看出哪些特色互相关联,哪些不相干。你应该晓得有正相干和负相关(深蓝色和深红色)。没有相关性的特色是红色的。
有几组正相干的特色,毫不奇怪,它们指的是同一类型的测量(例如 station_min_temp_c 和 station_avg_temp_c 之间的相关性)。但在不同的特色之间也存在相关性(比方 reanalysis_specific_humidity_g_per_kg 和 reanalysis_dew_point_temp_k)。咱们还应该关注 total_cases 和其余特色之间的相关性,因为这是咱们须要预测的。
这次咱们背运了,因为没有什么货色和咱们的指标有很强的相关性。然而咱们依然应该可能为咱们的模型抉择最重要的特色。当初看热图没什么用,让我切换到条形图。
sorted_y = corr.sort_values(by='total_cases', axis=0).drop('total_cases')
plt.figure(figsize=(20, 10))
ax = sns.barplot(x=sorted_y.total_cases, y=sorted_y.index, color="b")
ax.set_title('Correlation with total_cases in"sj"')
通常,在为模型抉择特色时,咱们抉择的特色与指标的相对相干值最高。这取决于你决定你抉择多少特色,你甚至能够抉择所有的特色,但这通常不是最好的主见。
察看目标值在数据集中是如何散布的也是很重要的。咱们能够很容易地用 pandas 做到:
均匀一周的病例数相当少。只是偶然(一年一次),案件总数会跳到某个更高的数值。在设计咱们的模型时,咱们须要记住这一点,因为即便咱们设法找到了“跳跃”,咱们可能会在几周内得分损失惨重,因为跳跃这种状况简直没有样本。
什么是 NDVI 值?
本文最初要探讨的是 NDVI 指数(归一化差别植被指数)。这个指数是植被的指标。高负值对应于水,靠近 0 的值示意岩石 / 沙子 / 雪,值靠近 1 寒带森林。在给定的数据集中,每个城市有 4 个不同的 NDVI 值(每个值对应于地图上不同的角落)。
即便总体 NDVI 指数对于理解咱们正在解决的地形类型十分有用。如果咱们须要为多个城市设计一个模型,地形类型的特色可能会很有用,但在这种状况下,咱们只已知两个城市的气象和地位。咱们不须要训练咱们的模型来判断咱们所处的环境,相同,咱们能够为每个城市训练不同的模型。
我花了一段时间尝试应用这些值(尤其是在这种状况下插值很艰难,因为咱们在这个过程中应用了大量的信息)。应用 NDVI 指数也可能产生误导,因为数值的变动并不一定与植被过程的变动绝对应。
论断
当初,你应该晓得咱们的数据集是什么样子的。咱们甚至还没有开始设计第一个模型,但曾经晓得有些特色不如其余特色重要,有些只是反复的数据。如果你须要从这整篇文章中失去一件事,那就是“首先试着了解你的数据!”.
参考文献:
DengAI: Predicting Disease Spread https://www.drivendata.org/co…
原文链接:https://towardsdatascience.co…
欢送关注磐创 AI 博客站:
http://panchuang.net/
sklearn 机器学习中文官网文档:
http://sklearn123.com/
欢送关注磐创博客资源汇总站:
http://docs.panchuang.net/