电动汽车充电站充电量预测_学习笔记(二)——特征优化

赛题分析

        本次竞赛的目标是:根据2014.4.15~2015.4.14一年中,0~499总共500个场站的每日充电量数据,以及其他相关数据,预测接下来一周的各个场站的每日充电量。

        stub_info.csv在测试集和训练集中一致,记录了每个场站的地理、性能等信息。

        power.csv仅在训练集中出现,记录了2014.4.15~2015.4.14一年中,0~499总共500个场站的每日充电量数据。

        power_forecast_history.csv在测试集和训练集中不同,记录着各个场站每日24小时的收费情况等信息。

        由上文的数据探索容易发现:

  1. power_forecast_history.csv表中,同一场站中单日的各小时的数据基本相同,可以以场站编号和日期为组合标签,进行聚合排重;
  2. 日期信息在baseline基础上,还可挖掘出节假日特征;
  3. h3编码未被使用,有待解析,用于提取特征。

初步处理

# 数据格式处理
import pandas as pd

# 设置数据集路径
path = r'E:\编程\电动汽车充电站充电量预测'

# 读取数据
train_power_forecast_history = pd.read_csv(path + r'\训练集\power_forecast_history.csv')
test_power_forecast_history = pd.read_csv(path + r'\测试集\power_forecast_history.csv')
train_power = pd.read_csv(path + r'\训练集\power.csv')
stub_info = pd.read_csv(path + r'\训练集\stub_info.csv')

# 聚合数据
'''head(1):1~24h数据重复,只取各场站第1小时,即每个分组第一行的数据'''
train_df = train_power_forecast_history.groupby(['id_encode', 'ds']).head(1)
del train_df['hour']

test_df = test_power_forecast_history.groupby(['id_encode', 'ds']).head(1)
del test_df['hour']

tmp_df = train_power.groupby(['id_encode', 'ds'])['power'].sum()
tmp_df.columns = ['id_encode', 'ds', 'power']

# 合并充电量数据
train_df = train_df.merge(tmp_df, on=['id_encode', 'ds'], how='left')

# 合并站点静态数据
train_df = train_df.merge(stub_info, on='id_encode', how='left')
test_df = test_df.merge(stub_info, on='id_encode', how='left')

# 数据变换
train_df['flag'] = train_df['flag'].map({'A': 0, 'B': 1})
test_df['flag'] = test_df['flag'].map({'A': 0, 'B': 1})

# 保存
train_df.to_csv(path + r'\process1\train_df1.csv', index=False)
test_df.to_csv(path + r'\process1\test_df1.csv', index=False)

时序特征

# 数据格式处理
import pandas as pd

# 时间特征提取
import datetime

# 设置数据集路径
path = r'E:\编程\电动汽车充电站充电量预测'

# 读取数据
train_df = pd.read_csv(path + r'\process1\train_df1.csv')
test_df = pd.read_csv(path + r'\process1\test_df1.csv')


# 获取节假日列表
def get_holiday_set():
    holiday_set = set()
    '''取并集,实现集合的多元素添加'''
    # 清明节
    holiday_set = holiday_set | {datetime.date(2023, 4, 5)}
    # 劳动节
    holiday_set = holiday_set | {datetime.date(2022, 4, 30), datetime.date(2022, 5, 1), datetime.date(2014, 5, 2),
                                 datetime.date(2022, 5, 3), datetime.date(2022, 5, 4)}
    # 端午节
    holiday_set = holiday_set | {datetime.date(2022, 6, 3), datetime.date(2022, 6, 4), datetime.date(2022, 6, 5)}
    # 中秋节
    holiday_set = holiday_set | {datetime.date(2022, 9, 10), datetime.date(2022, 9, 11), datetime.date(2022, 9, 12)}
    # 国庆节
    holiday_set = holiday_set | {datetime.date(2022, 10, 1), datetime.date(2022, 10, 2), datetime.date(2022, 10, 3),
                                 datetime.date(2022, 10, 4), datetime.date(2022, 10, 5), datetime.date(2022, 10, 6),
                                 datetime.date(2022, 10, 7)}
    # 元旦节
    holiday_set = holiday_set | {datetime.date(2022, 12, 31), datetime.date(2023, 1, 1), datetime.date(2023, 1, 2)}
    # 春节
    holiday_set = holiday_set | {datetime.date(2023, 1, 21), datetime.date(2023, 1, 22), datetime.date(2023, 1, 23),
                                 datetime.date(2023, 1, 24), datetime.date(2023, 1, 25), datetime.date(2023, 1, 26),
                                 datetime.date(2023, 1, 27)}

    return holiday_set


# 定义提取时间戳的方法
def get_time_feature(df, col):
    # 浅拷贝原表,保护原数据
    df_copy = df.copy()
    # 统一格式:ds_
    prefix = col + "_"
    # 命名新字段,用于储存日期数据
    df_copy['new_' + col] = df_copy[col].astype(str)
    # 统一格式:new_ds
    col = 'new_' + col
    # 将MySQL类型日期数据转化为’年月日‘日期格式
    df_copy[col] = pd.to_datetime(df_copy[col], format='%Y%m%d')
    df_copy[prefix + 'year'] = df_copy[col].dt.year     # 从日期字段提取年特征
    df_copy[prefix + 'month'] = df_copy[col].dt.month   # 月
    df_copy[prefix + 'day'] = df_copy[col].dt.day       # 日
    # 星期:1=日,2=星期一,3=星期二,4=星期三,5=星期四,6=星期五,7=星期六
    df_copy[prefix + 'dayofweek'] = df_copy[col].dt.dayofweek
    # 周末判断:1=周末
    df_copy[prefix + 'is_wknd'] = df_copy[col].dt.dayofweek // 6
    # 季度:1~4
    df_copy[prefix + 'quarter'] = df_copy[col].dt.quarter
    # 月初判断:返回值为布尔值,再转化为int整数类型
    df_copy[prefix + 'is_month_start'] = df_copy[col].dt.is_month_start.astype(int)
    # 月末判断
    df_copy[prefix + 'is_month_end'] = df_copy[col].dt.is_month_end.astype(int)
    # 月中判断
    df_copy[prefix + 'is_month_mid'] = 0
    df_copy.loc[(10 < df_copy[prefix + 'day']) & (df_copy[prefix + 'day'] <= 20), prefix + 'is_month_mid'] = 1
    # 节假期判断
    df_copy[prefix + 'is_holiday'] = 0
    df_copy.loc[df_copy[col].isin(get_holiday_set()), prefix + 'is_holiday'] = 1

    del df_copy[col]

    return df_copy


# 提取时间特征
train_df = get_time_feature(train_df, 'ds')
test_df = get_time_feature(test_df, 'ds')

# 保存
train_df.to_csv(path + r'\process2\train_df2.csv', index=False)
test_df.to_csv(path + r'\process2\test_df2.csv', index=False)

地理特征

解码
# 数据格式处理
import pandas as pd

# 向服务器发送并响应HTTP请求
import requests
import urllib

# 加密或检验文件一致性
import hashlib

# 解读H3编码
from h3 import h3

# 绘制地图
import folium
from IPython.display import display

# 设置数据集路径
path = r'E:\编程\电动汽车充电站充电量预测'

# 读取数据
stub_info = pd.read_csv(path + r'\训练集\stub_info.csv')

# 把H3编码转换成经纬度坐标
stub_info['center'] = stub_info['h3'].apply(lambda x: h3.h3_to_geo(x))


# 定义地图绘制方法
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


# 绘制地图
si_m = geo_map(stub_info)
display(si_m)

# 调取百度api获取经纬度对应地址信息
'''进入百度web服务api网站注册账号, 获取对应的 ak 跟 sk, 
网站指引https://lbsyun.baidu.com/faq/api?title=webapi'''


# 建立访问函数
def get_city_frombd(row):
    # 服务地址
    host = "https://api.map.baidu.com"
    # 接口地址
    uri = "/reverse_geocoding/v3"
    # 在控制台-应用管理-创建应用后获取的AK
    ak = "rYyvcdfmliu8GsrGoycIRdrSvO2gcMfy"
    # 在控制台-应用管理-创建应用时,校验方式选择sn校验后生成的SK
    sk = "MjFcjMs935IeZEU2xG5QAsIaOBXMEtwx"
    # 设置请求参数
    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


# 解码
si_df = df_stub_process(stub_info)

# 保存
si_df.to_csv(path + r'\process3\map.csv', index=False)
编码 
# 数据格式处理
import numpy as np
import pandas as pd

# 设置数据集路径
path = r'E:\编程\电动汽车充电站充电量预测'

# 读取数据
train_df = pd.read_csv(path + r'\process2\train_df2.csv')
test_df = pd.read_csv(path + r'\process2\test_df2.csv')
map_df = pd.read_csv(path + r'\process3\map.csv')


# 地址编码
def onethot(d):
    # 一维数组初始化
    v = np.zeros(1)
    # str -> dict
    d = eval(d)
    # 输入地址编码
    v[0] = d['adcode']
    return v


# 提取城市位置特征
city = pd.DataFrame(np.vstack(map_df['address'].apply(onethot)))
city.columns = ['city']
city['a'] = 100
city['city'] //= city['a']

# 将经纬度坐标与城市位置并入数据集
map_df = pd.concat([map_df, city], axis=1)
map_df = map_df.drop(['address', 'center', 'id_encode', 'a'], axis=1)
train_df = pd.concat([train_df, map_df], axis=1)
test_df = pd.concat([test_df, map_df], axis=1)

# 保存
train_df.to_csv(path + r'\process3\train_df3.csv', index=False)
test_df.to_csv(path + r'\process3\test_df3.csv', index=False)
map_df.to_csv(path + r'\process3\map_df0.csv', index=False)

小结

        根据步骤逐级保存阶段结果文件,有利于节省时间和运算量,便于模块化分析和数据管理。需要注意的是,申请第三方运算资源有每日运算量限制,要及时保存数据。

        接下来准备进行特征组合方向的尝试。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值