学习日记——SEED新能源赛道特征处理

本次任务解决两个问题:

1)h3编码转换,获得站点的经纬度以及其他地理数据

2)处理训练集中的站点发电量的异常值

1、h3+逆编码转化

首先安装h3(pip install h3),需要看地图再安装一个folium(pip install folium),然后开始写代码转换。

from h3 import h3
from IPython.display import display
df_stub_train = pd.read_csv('./data1/train/stub_info.csv')
df_stub_test = pd.read_csv('./data1/test/stub_info.csv')
df_stub_train['center'] = df_stub_train['h3'].apply(lambda x: h3.h3_to_geo(x))
df_stub_test['center'] = df_stub_test['h3'].apply(lambda x: h3.h3_to_geo(x))
#print(df_stub.head())

# 绘制地图
import folium
def geo_map(df):
    # 拆分经纬度坐标
    df[['latitude', 'longitude']] = pd.DataFrame(df['center'].tolist(), columns=['latitude', 'longitude'])
    

    # 创建地图
    m = folium.Map(location=[df['latitude'].mean(), df['longitude'].mean()], zoom_start=10)

    # 添加标记点
    for index, row in df.iterrows():
        folium.Marker(
            location=[row['latitude'], row['longitude']],
            popup=row['id_encode']
        ).add_to(m)
  # 显示地图
    return m

stub_m_train = geo_map(df_stub_train)
stub_m_test = geo_map(df_stub_test)
#display(stub_m)
stub_m_train.save('map.html')

用到了h3_to_geo(),它是一个将 H3 地理编码转换为经纬度坐标的函数。将训练集和测试集的站点进行h3解码,再将经度、纬度单独划分成列作为特征。

为了获取更多地理信息,去百度地图申请一个全球逆编码转换api接口。

####################################### 调取百度api获取经纬度对应地址信息
# 需要先进入百度web服务api网站注册账号, 获取对应的ak 跟sk, 需阅读网站指引
# https://lbsyun.baidu.com/faq/api?title=webapi
# 里面有不少案例, 以下代码也是直接引用上面提供的案例代码
# 直接用的话需要提供代码中的 ak 跟 sk 两个key

# encoding:utf-8
# 根据您选择的AK已为您生成调用代码
# 检测您当前的AK设置了sn检验,本示例中已为您生成sn计算代码
import requests
import urllib
import hashlib
# 建立访问函数
def get_city_frombd(row):
    # 服务地址
    host = "https://api.map.baidu.com"
    # 接口地址
    uri = "/reverse_geocoding/v3"
    # 此处填写你在控制台-应用管理-创建应用后获取的AK
    ak = "OkLKwnGpGvG7QnzA1tHQPi1KLGHS37Og"
    # 此处填写你在控制台-应用管理-创建应用时,校验方式选择sn校验后生成的SK
    sk = "KGczW3bY6CxqAaRZm7C8R7oTXMXqCgXD"
    # 设置您的请求参数
    coordinate = str(row['latitude']) + ',' + str(row['longitude'])
params = {
        "ak":       ak,
        "output":    "json",
        "coordtype":    "wgs84ll",
        "extensions_poi":    "0",
        "location":   coordinate,
    }
     # 拼接请求字符串
    paramsArr = []
    for key in params:
        paramsArr.append(key + "=" + params[key])
    queryStr = uri + "?" + "&".join(paramsArr)

    # 对queryStr进行转码,safe内的保留字符不转换
    encodedStr = urllib.request.quote(queryStr, safe="/:=&?#+!$,;'@()*[]")

    # 在最后直接追加上您的SK
    rawStr = encodedStr + sk

    # 计算sn
    sn = hashlib.md5(urllib.parse.quote_plus(rawStr).encode("utf8")).hexdigest()

    # 将sn参数添加到请求中
    queryStr = queryStr + "&sn=" + sn

    # 请注意,此处打印的url为非urlencode后的请求串
    # 如果将该请求串直接粘贴到浏览器中发起请求,由于浏览器会自动进行urlencode,会导致返回sn校验失败
url = host + queryStr
    response = requests.get(url)
    return response.json().get('result')#.get('addressComponent')

def df_stub_process(df):
    df['center'] = df['h3'].apply(lambda x: h3.h3_to_geo(x))
    df[['latitude', 'longitude']] = pd.DataFrame(df['center'].tolist(), columns=['latitude', 'longitude'])
    df['latitude'] = df['latitude'].apply(lambda x: round(x,6))
    df['longitude'] = df['longitude'].apply(lambda x: round(x,6))
    # 通过百度api返回城市信息
    df['address'] = df[['latitude','longitude']].apply(get_city_frombd, axis = 1)
    return df

df_stub_train = df_stub_process(df_stub_train)
df_stub_test = df_stub_process(df_stub_test)

以上代码为网站提供,只需定义一个函数调用即可,运行后就可以得到站点的地理信息,例如站点0的地理信息如下:

'location': {'lng': 120.10799201951572, 'lat': 31.52773196756505}, 'formatted_address': '江苏省常州市武进区陆马公路', 
'edz': {'name': ''}, 
'business': '', 
'addressComponent': {'country': '中国', 'country_code': 0, 'country_code_iso': 'CHN', 'country_code_iso2': 'CN', 'province': '江苏省', 'city': '常州市', 'city_level': 2, 'district': '武进区', 'town': '雪堰镇', 'town_code': '320412110', 'distance': '', 'direction': '', 'adcode': '320412', 'street': '陆马公路', 'street_number': ''}, 
'pois': [], 
'roads': [], 
'poiRegions': [], 
'sematic_description': '', 
'formatted_address_poi': '', 
'cityCode': 348

2、处理发电量异常值

首先筛选一些站点的发电量值绘制曲线,观察大致趋势。这里选择0,1,2,3,4五个站点,代码同任务一,一年中每天的充电量曲线如下:

由上图可以发现,站点0和站点2都出现了异常低的充电量数值,站点4出现异常高的充电量数值。所以决定先确定异常值的具体位置,再用各自对应站点一年发电量的平均值来替代。

#寻找异常值,先挑选一个大致范围
tmp_df1=train_df[train_df['id_encode']==0]['power']
print(tmp_df1[260:270])
tmp_df2=train_df[train_df['id_encode']==2]['power'].reset_index(drop=True)
tmp_df2=tmp_df2.reset_index(drop=True).reset_index()
print(tmp_df2[220:230])
tmp_df3=train_df[train_df['id_encode']==4]['power'].reset_index(drop=True)
tmp_df3=tmp_df3.reset_index(drop=True).reset_index()
print(tmp_df3[75:90])

通过观察输出的结果列表,确定异常数据位置:

1)站点0第261行(即第262天)充电量为0,异常低,填充站点0均值。

2)站点2在第225-第237行充电量为0,异常低,填充站点2均值 (不重新索引即为955-967行)

3)站点4在83行充电量为1090.4430,第84行充电量为534.8400,第85行充电量为2126.4200,异常高,填充站点4均值 (不重新索引即为1543-1545行)

#更改异常值
train_df['power'].iat[261]=train_df.loc[train_df['id_encode'] == 0, 'power'].mean()
print(train_df['power'].iloc[261])
train_df.loc[955:967,'power']=train_df.loc[train_df['id_encode'] == 2, 'power'].mean()
print(train_df.loc[955:967,'power'])
train_df.loc[1543:1545,'power']=train_df.loc[train_df['id_encode'] == 4, 'power'].mean()
print(train_df.loc[1543:1545,'power'])

接着对应更改异常值,再重新观察更改过后的五个站点一年内的充电量曲线,可以看到已取去除尖刺,大致在一个范围内波动。

最后将这些处理过的特征重新聚合,再次训练即可。

本次学习任务不足即待改进之处:

 1)写完打卡文章才发现在处理异常值时只考虑到了前5个站点,得改进。

2)只在任务一的基础上加了经纬度特征,得把逆编码解码后的更多地理信息也划分成数据集,不然无引入逆编码的意义。

3)提交后发现分数并未大幅提高,甚至在做完异常值平均处理后分数下降了不少,感觉是异常值的处理出了问题,这一点也需要继续思考。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值