使用学习过的知识(Numpy数值分析基础、Matplotlib数据可视化基础、Pandas统计分析基础),对data.csv用户用户用电量数据进行相关处理,其中数据中有编号为1-200的200位电力用户,DATA_DATE表示时间,如2015/1/1表示2015年1月1日,KWH为用电量。请完成以下工作:
一、将数据进行转置,转置后行为用户编号、列为日期、值为用户每日用电量。
二、对数据中的异常数据进行识别并处理。
三、统计每个用户用电数据的基本统计量,包括:最大值、最小值、均值、中位数、和、方差、偏度、峰度。
四、每个用户用电数据按日差分,并求取差分结果的基本统计量,统计量同三。
五、求取每个用户的5%分位数。
六、每个用户按周求和并差分(一周7天,年度分开),并求取差分结果的基本统计量,统计量同三。
七、统计每个用户的日用电量在其最大值0.9倍以上的次数。
八、求取每个用户日为最大值/最小值的索引月份,若最大值/最小值存在于多个月份中,则输出含有最大值/最小值最多的那个月份。如1号用户的最小值为0,则看哪个月的0最多。
九、求取每个用户七八月电量和与三四月电量和的比值,最大值的比值,最小值的比值,均值(日均电量)的比值。
十、合并上述特征。
import pandas as pd
data = pd.read_csv('./data/data.csv', encoding='gbk')
# 转置data
# result = data.reset_index().pivot('CONS_NO', 'DATA_DATE', 'KWH')
data['DATA_DATE'] = pd.to_datetime(data['DATA_DATE'])
result = pd.pivot_table(data, index='CONS_NO', columns='DATA_DATE')
print(result)
导入pandas,导入data.csv文件同时编码设置为GBK,把DATA_DATE转换为时间序列,使用透视表将index设置为’CONS_NO’,columns设置为’DATA_DATE’。
注意:若此处不把DATA_DATE转换成时间序列,那么columns的排列顺序将不是按照时间顺序,而是按照数字顺序。例:未转换时,顺序为2015/1/1, 2015/1/10, 2015/1/11 , …;转换后,顺序为2015/1/1, 2015/1/2 , 2015/1/3 , …。
# 异常值识别处理
null_value = data.isnull().sum() # 缺失值识别
print("data具有的缺失值:\n",null_value)
data.fillna(method='pad', inplace=True) # 缺失值处理方法:用前一个数据进行填充
null_value = data.isnull().sum()
print("data处理缺失值之后:\n",null_value)
u = data['KWH'].mean()
o = data['KWH'].std()
three_uo = data['KWH'].apply(lambda x: x>u+3*o or x<u-3*o)
result1 = data.loc[three_uo, 'KWH'] # 使用3σ方法识别异常值
print("data在3σ下具有的异常值:\n",result1)
使用导入的data数据进行缺失值识别,识别方法为isnull结合sum方法确定缺失值的个数,再使用fillna方法填充缺失值;异常值识别方法为3σ方法识别异常值。偷懒了没有对异常值进行处理
说明:
pandas提供了识别缺失值的方法isnull以及识别非缺失值的方法nonull,这两种方法在使用时返回的都是bool值True和False,结合sum函数,可以检测数据中缺失值的分布以及数据中一共含有多少缺失值。isnull和nonull之间的结果正好相反。
处理缺失值有三种方法:
删除法 —— 删除法可以分为删除观测记录和删除特征两种,它属于利用减少样本量来换取信息完整度的一种方法,是一种最简单的缺失值处理方法。pandas中提供了简便的删除缺失值的方法 dropna ,该方法既可以删除观测记录,亦可以删除特征。
替换法 —— 特征可分为和。当缺失值所在特征为时,通常利用其均值、中位数和众数等描述其集中趋势的统计量来代替缺失值;当缺失值所在特征为时,则使用众数来替换缺失值。***PS:*这里使用了pandas提供的 fillna 方法进行缺失值替换,原理是当 method 为 pad 时使用上一个非缺失值填补缺失值,当 method 为 bfill 时使用下一个非缺失值填补缺失值。
数值型
类别型
数值型
类别型
插值法 —— 删除法简单,但是会引起数据结构的变动,样本减少;替换法使用难度低,但是会影响数据的标准差,导致信息量变动。所以除了上面两种方法,还有一种方法为插值法。常用的插值法有、和。是一种较为简单的插值方法,他针对已知的值求出线性方程,通过求解线性方程得到缺失值;是利用已知的值拟合一个多项式,使得现有的数据满足这个多项式,再利用这个多项式求解缺失值,常见的多项式插值法有拉格朗日插值和牛顿插值等;是以可变的样条来作出一条经过一系列点的光滑曲线的插值方法,插值样条由一些多项式组成,每一个多项式都是由相邻两个数据点决定,这样可以保证两个相邻多项式及其导数在连接处连续。
线性插值
多项式插值
样条插值
线性插值
多项式插值
样条插值
异常值是指数据中个别值的数值明显偏离其余的数值,有时也成为离群点,检测异常值就是检验数据中是否有录入错误以及是否含有不合理的数据。异常值的检测常用的有两种方法,3σ原则和箱线图分析。
# 求每个用户的统计量
def statistics(df): # 数据统计并合并统计量
surface = pd.concat([df.min(), df.max(), df.mean(), df.median(), df.sum(), df.var(), df.skew(), df.kurt()],
axis=1)
surface.columns = ['min', 'max', 'mean', 'median', 'sum', 'var', 'skew', 'kurt']
return surface
print("每个用户用电数据的基本统计量:\n",statistics(result.T))
这里使用了自定义函数,是为了之后的题做准备。
数据使用了转置之后的数据result,再进行转置,调用statistics方法进行数据统计并合并统计量。
statistics中使用了pandas.concat方法,这个方法可以用来对表进行纵向堆叠,在默认情况下,即axis=0时,concat做列对齐,将不同行索引的两张或多张表纵向合并。
# 每个用户用电数据按日差分
different = result.T.diff(1) # 对转置后的dataframe进行按日差分
print("每个用户用电数据按日差分:\n",different)
print("每个用户用电数据按日差分的基本统计量:\n",statistics(different))
这里使用result转置,并调用diff方法进行数据的按日差分。
调用statistics,对按日差分的数据进行统计,并输出所有的基本统计量。
print("每个用户的5分位数为:\n",result.T.describe(percentiles=[0.05]))
使用describe方法统计每个用户的5%分位数。
# 每个用户按周求和并差分
data['DATA_DATE'] = pd.to_datetime(data['DATA_DATE'])
key = pd.PeriodIndex(data['DATA_DATE'], freq='w')
sum_week = data.groupby(by=['CONS_NO', key]).sum()
a = pd.pivot_table(sum_week, index='DATA_DATE', columns='CONS_NO')
different = a.diff(1)
print("每个用户按周求和并差分:\n",different)
print("每个用户按周求和并差分的基本统计量:\n",statistics(different))
对DATA_DATE进行时间序列转换。(由于第一题已经转换过了,这里可以不用再转换了)
frep='w’使DATA_DATE按周的频率排列,同时获取其索引。PS:这里好像没有把年度分开
按照CONS_NO及key进行分组,并求和。(完成按周求和操作)
创建透视表,并差分,最后使用statistics统计基本统计量。
a = result.T.apply(lambda x:x>x.max()*0.9).sum()
print("每个用户日用电量在其最大值0.9倍以上的次数:\n",a)
使用apply方法
# 输出含有最大值/最小值最多的那个月份
print("输出含有最大值/最小值最多的那个月份:")
key = pd.PeriodIndex(data['DATA_DATE'], freq='m')
month = data.groupby(by=['CONS_NO', key])['KWH'].max()# 按月进行分组
month_df = pd.DataFrame(month)
max_index = month_df.reset_index().groupby('CONS_NO')['KWH'].idxmax()
max_value = month_df.iloc[max_index]
max_value.columns = ['各用户的KWH最大值']
print(max_value) # 输出含有最大值最多的那个月份
min_index = data[(data.KWH == data.KWH.min())].index
surface_min = data.iloc[min_index]
key = pd.PeriodIndex(surface_min['DATA_DATE'], freq='m')
min_count = surface_min.groupby(by=['CONS_NO', key])['KWH'].count()# 按月进行分组
min_count_df = pd.DataFrame(min_count)
min_count_df_index = min_count_df.reset_index().groupby('CONS_NO')['KWH'].idxmax()
min_value = min_count_df.iloc[min_count_df_index]
min_value.columns = ['KWH最小值次数']
print(min_value) # 输出含有最小值最多的那个月份
于第六题相似,使用了PeriodIndex方法使得DATA_DATE以月为单位进行分组。
之后,由于groupby得到的是serise类,所以将month转换为dataframe类并结合reset_index与idxmax方法获取含有最大值最多的那个月份的索引。
将获得的索引使用iloc进行切片,得到所需结果。
输出含有最小值最多的那个月份的方法与输出含有最大值最多的那个月份的方法相似,但是需要对最小值进行比较,并求出每月最小值的个数。
PS:这道题重复代码有点多,所以肯定不是最优答案,所以仅供参考。(求的是)
https://private.codecogs.com/gif.latex?%5Cfrac%7BJuly+August%7D%7BMarch+April%7D
def date_filter(df): # 日期筛选,选出三四月份,七八月份,返回两张表
idx = pd.IndexSlice
s_e = df.loc[idx[:,['2015-7','2015-8', '2016-7', '2016-8']],:]
t_f = df.loc[idx[:,['2015-3','2015-4', '2016-3', '2016-4']],:]
return s_e, t_f
def date_merge(df_1, df_2, name): # 合并符合要求的日期,同时进行比值处理,返回题解
df_ratio = pd.merge(df_1, df_2, on='CONS_NO')
df_ratio.columns = ['7-8月', '3-4月']
df_ratio[name] = df_ratio['7-8月'] / df_ratio['3-4月']
return df_ratio
key = pd.PeriodIndex(data['DATA_DATE'], freq='m')
month = data.groupby(by=['CONS_NO', key])# 按月进行分组
month_sum = month.sum() # 求和的比值
s_e_1, t_f_1= date_filter(month_sum)
s_e_sum = s_e_1.groupby('CONS_NO').sum()
t_f_sum = t_f_1.groupby('CONS_NO').sum()
se_tf_sum_ratio = date_merge(s_e_sum, t_f_sum, 'sum_ratio')
print("每个用户七八月电量和与三四月电量和的比值:\n",se_tf_sum_ratio)
month_max = month.max() # 求最大值的比值
s_e_2, t_f_2 = date_filter(month_max)
s_e_max = s_e_2.groupby('CONS_NO').max().loc[:,'KWH']
t_f_max = t_f_2.groupby('CONS_NO').max().loc[:,'KWH']
se_tf_max_ratio = date_merge(s_e_max, t_f_max, 'max_ratio')
print("每个用户七八月电量最大值与三四月电量最大值的比值:\n",se_tf_max_ratio)
month_min = month.min() # 求最小值的比值
s_e_3, t_f_3 = date_filter(month_min)
s_e_min = s_e_3.groupby('CONS_NO').min().loc[:,'KWH']
t_f_min = t_f_3.groupby('CONS_NO').min().loc[:,'KWH']
se_tf_min_ratio = date_merge(s_e_min, t_f_min, 'min_ratio')
print("每个用户七八月电量最小值与三四月电量最小值的比值:\n",se_tf_min_ratio)
month_mean_sum= month.sum() # 求平均值的比值
s_e_4, t_f_4 = date_filter(month_mean_sum)
s_e_mean = s_e_4.groupby('CONS_NO').apply(lambda x:x.sum()/122) # 先计算每个用户七八月份总的用电量,然后除以总天数,得到平均值
t_f_mean = t_f_4.groupby('CONS_NO').apply(lambda x:x.sum()/122) # 同上
se_tf_mean_ratio = date_merge(s_e_mean, t_f_mean, 'mean_ratio')
print("每个用户七八月电量平均值与三四月电量平均值的比值:\n",se_tf_mean_ratio)
第一个自定义函数date_filter的作用是进行日期的筛选,选出每年七八月份与每年三四月份;一个参数接收一个表,返回两个表。
第二个自定义函数date_merge的作业是合并符合要求的日期同时进行比值的处理;三个参数接收两个表一个字符串,返回一个表。
以求和的比值为例:
先将DATA_DATE按照月分组,并求和。
调用date_filter方法分离七八月份与三四月份,并分别求和。
调用date_merge方法将两张已经求和的七八月份和三四月份的表合并,并将求比值的列取名叫sum_ratio。
注意:求平均值的比值时,求平均值的方法是用求和并除以122(总天数)得到平均值。
# 合并特征
all_trait = pd.concat([se_tf_sum_ratio.loc[:,'sum_ratio'],
se_tf_max_ratio.loc[:,'max_ratio'],
se_tf_min_ratio.loc[:,'min_ratio'],
se_tf_mean_ratio.loc[:,'mean_ratio']],
axis=1)
print("合并特征:\n",all_trait)
方法与第三题相似
PS:题目给的参考答案是把第一至第九题的结果合并,但我理解成了将第九题的特征合并。
PS:这是我的python数据分析与应用的大作业(非参考答案,参考需谨慎)
PS:这是我的python数据分析与应用的大作业(非参考答案,参考需谨慎)
import pandas as pd
data = pd.read_csv('./data/data.csv', encoding='gbk')
# 转置data
# result = data.reset_index().pivot('CONS_NO', 'DATA_DATE', 'KWH')
data['DATA_DATE'] = pd.to_datetime(data['DATA_DATE'])
result = pd.pivot_table(data, index='CONS_NO', columns='DATA_DATE')
print(result)
# 异常值识别处理
null_value = data.isnull().sum() # 缺失值识别
print("data具有的缺失值:\n",null_value)
data.fillna(method='pad', inplace=True) # 缺失值处理方法:用前一个数据进行填充
null_value = data.isnull().sum()
print("data处理缺失值之后:\n",null_value)
u = data['KWH'].mean()
o = data['KWH'].std()
three_uo = data['KWH'].apply(lambda x: x>u+3*o or x<u-3*o)
result1 = data.loc[three_uo, 'KWH'] # 使用3σ方法识别异常值
print("data在3σ下具有的异常值:\n",result1)
# 求每个用户的统计量
def statistics(df): # 数据统计并合并统计量
surface = pd.concat([df.min(), df.max(), df.mean(), df.median(), df.sum(), df.var(), df.skew(), df.kurt()],
axis=1)
surface.columns = ['min', 'max', 'mean', 'median', 'sum', 'var', 'skew', 'kurt']
return surface
print("每个用户用电数据的基本统计量:\n",statistics(result.T))
# 每个用户用电数据按日差分
different = result.T.diff(1) # 对转置后的dataframe进行按日差分
print("每个用户用电数据按日差分:\n",different)
print("每个用户用电数据按日差分的基本统计量:\n",statistics(different))
# 每个用户的5%分位数
print("每个用户的5分位数为:\n",result.T.describe(percentiles=[0.05]))
# 每个用户按周求和并差分
data['DATA_DATE'] = pd.to_datetime(data['DATA_DATE'])
key = pd.PeriodIndex(data['DATA_DATE'], freq='w')
sum_week = data.groupby(by=['CONS_NO', key]).sum()
a = pd.pivot_table(sum_week, index='DATA_DATE', columns='CONS_NO')
different = a.diff(1)
print("每个用户按周求和并差分:\n",different)
print("每个用户按周求和并差分的基本统计量:\n",statistics(different))
# 每个用户的日用电量在其最大值0.9倍以上的数据
a = result.T.apply(lambda x:x>x.max()*0.9).sum()
print("每个用户日用电量在其最大值0.9倍以上的次数:\n",a)
# 第八题,输出含有最大值/最小值最多的那个月份
print("输出含有最大值/最小值最多的那个月份:")
key = pd.PeriodIndex(data['DATA_DATE'], freq='m')
month = data.groupby(by=['CONS_NO', key])['KWH'].max()# 按月进行分组
month_df = pd.DataFrame(month)
max_index = month_df.reset_index().groupby('CONS_NO')['KWH'].idxmax()
max_value = month_df.iloc[max_index]
max_value.columns = ['各用户的KWH最大值']
print(max_value) # 输出含有最大值最多的那个月份
min_index = data[(data.KWH == data.KWH.min())].index
surface_min = data.iloc[min_index]
key = pd.PeriodIndex(surface_min['DATA_DATE'], freq='m')
min_count = surface_min.groupby(by=['CONS_NO', key])['KWH'].count()# 按月进行分组
min_count_df = pd.DataFrame(min_count)
min_count_df_index = min_count_df.reset_index().groupby('CONS_NO')['KWH'].idxmax()
min_value = min_count_df.iloc[min_count_df_index]
min_value.columns = ['KWH最小值次数']
print(min_value) # 输出含有最小值最多的那个月份
# 每个用户七八月电量和与三四月电量和的比值
def date_filter(df): # 日期筛选,选出三四月份,七八月份,返回两张表
idx = pd.IndexSlice
s_e = df.loc[idx[:,['2015-7','2015-8', '2016-7', '2016-8']],:]
t_f = df.loc[idx[:,['2015-3','2015-4', '2016-3', '2016-4']],:]
return s_e, t_f
def date_merge(df_1, df_2, name): # 合并符合要求的日期,同时进行比值处理,返回题解
df_ratio = pd.merge(df_1, df_2, on='CONS_NO')
df_ratio.columns = ['7-8月', '3-4月']
df_ratio[name] = df_ratio['7-8月'] / df_ratio['3-4月']
return df_ratio
key = pd.PeriodIndex(data['DATA_DATE'], freq='m')
month = data.groupby(by=['CONS_NO', key])# 按月进行分组
month_sum = month.sum() # 求和的比值
s_e_1, t_f_1= date_filter(month_sum)
s_e_sum = s_e_1.groupby('CONS_NO').sum()
t_f_sum = t_f_1.groupby('CONS_NO').sum()
se_tf_sum_ratio = date_merge(s_e_sum, t_f_sum, 'sum_ratio')
print("每个用户七八月电量和与三四月电量和的比值:\n",se_tf_sum_ratio)
month_max = month.max() # 求最大值的比值
s_e_2, t_f_2 = date_filter(month_max)
s_e_max = s_e_2.groupby('CONS_NO').max().loc[:,'KWH']
t_f_max = t_f_2.groupby('CONS_NO').max().loc[:,'KWH']
se_tf_max_ratio = date_merge(s_e_max, t_f_max, 'max_ratio')
print("每个用户七八月电量最大值与三四月电量最大值的比值:\n",se_tf_max_ratio)
month_min = month.min() # 求最小值的比值
s_e_3, t_f_3 = date_filter(month_min)
s_e_min = s_e_3.groupby('CONS_NO').min().loc[:,'KWH']
t_f_min = t_f_3.groupby('CONS_NO').min().loc[:,'KWH']
se_tf_min_ratio = date_merge(s_e_min, t_f_min, 'min_ratio')
print("每个用户七八月电量最小值与三四月电量最小值的比值:\n",se_tf_min_ratio)
month_mean_sum= month.sum() # 求平均值的比值
s_e_4, t_f_4 = date_filter(month_mean_sum)
s_e_mean = s_e_4.groupby('CONS_NO').apply(lambda x:x.sum()/122) # 先计算每个用户七八月份总的用电量,然后除以总天数,得到平均值
t_f_mean = t_f_4.groupby('CONS_NO').apply(lambda x:x.sum()/122) # 同上
se_tf_mean_ratio = date_merge(s_e_mean, t_f_mean, 'mean_ratio')
print("每个用户七八月电量平均值与三四月电量平均值的比值:\n",se_tf_mean_ratio)
# 合并特征
all_trait = pd.concat([se_tf_sum_ratio.loc[:,'sum_ratio'],
se_tf_max_ratio.loc[:,'max_ratio'],
se_tf_min_ratio.loc[:,'min_ratio'],
se_tf_mean_ratio.loc[:,'mean_ratio']],
axis=1)
print("合并特征:\n",all_trait)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-drU2OGwX-1634712263615)(https://img-bc.icode.best/20200412161028940.png)]
最后,这是我的python数据分析与应用的大作业(非参考答案,参考需谨慎),肯定有错的或者可以优化的地方欢迎指出。
今后可能会继续把上课内容及作业写出来。(大概,不懒的话)
PS:上传了大作业所需要的文件
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 本文链接: https://blog.csdn.net/Joker_Q/article/details/105459186