最新消息:XAMPP默认安装之后是很不安全的,我们只需要点击左方菜单的 "安全"选项,按照向导操作即可完成安全设置。

Python数据分析实战之技巧大全

XAMPP案例 admin 28浏览 0评论

数据分析实战中遇到的几个问题?

—— Pandas的DataFrame如何固定字段排序

—— 保证字段唯一性应如何处理

—— 透视表pivot_table函数转化长表注意问题

——Pandas的DataFrame数据框存在缺失值NaN运算如何应对

——如何对数据框进行任意行列增、删、改、查操作

—— 如何实现字段自定义打标签

Q1:Pandas的DataFrame如何固定字段排序

df_1 = pd.DataFrame({"itemtype": list(df.ITEMTYPE.unique())})
#固定字段顺序
list_custom = ["电耗量", "照明插座用电", "空调用电", "动力用电", "特殊用电"]

switch = {"电耗量": lambda x: list(x[x.ITEMTYPE == "电耗量"]["BRANCHID"]),
          "照明插座用电": lambda x: list(x[x.ITEMTYPE == "照明插座用电"]["BRANCHID"]),
          "空调用电": lambda x: list(x[x.ITEMTYPE == "空调用电"]["BRANCHID"]),
          "动力用电": lambda x: list(x[x.ITEMTYPE == "动力用电"]["BRANCHID"]),
          "特殊用电": lambda x: list(x[x.ITEMTYPE == "特殊用电"]["BRANCHID"])}

fxzl_list = []
fxmc_list = []
#列表生成式截留,其它方法参见推文Python实现switch/case用法案例
for i in [n for n in list_custom if n in list(df_1.itemtype)]:
    try:
        fxzl_list.append(switch[i](df))
        fxmc_list.append(i)
    except KeyError as e:
        pass
display(fxmc_list)
display(fxzl_list)

drb72

Q2:注意保证字段唯一性,如何处理

#以名称作为筛选字段时,可能出现重复的情况,实际中尽量以字段id唯一码与名称建立映射键值对,作图的时候尤其注意,避免不必要的错误,可以做以下处理:
1、处理数据以id为字段,最后统计用建立的key-value映射
X.index = X.index.map(_dict)
X1=X1.rename(columns=_dict)
2、加上区分字段
 p1=list(X1.columns)
 X2.columns=[p1[i]+"-"+str(i) for i in range(len(p1))]

当然也可以对图例标签进行自定义设置区分,具体参见推文Python图表自定义设置

Q3:透视表pivot_table函数转化长表注意问题

import pandas as pd
import numpy as np
#构建重塑时间序列
index=pd.DataFrame({"时间":pd.date_range(start="2019/1/1",end="2019/12/31",freq="d")})
#重塑对象清单
df_list=list(df.分项名称.unique())

# 构建空表,存储处理的对象
df_empty=pd.DataFrame(columns=["时间","分项名称","用电量"])
for j in range(len(df_list2)):
    df_1=df[df.分项名称==df_list2[j]]
#     df_1=df_1.drop_duplicates(subset=["时间"])
    DATA=pd.merge(index,df_1,how="left",on="时间")
    DATA["分项名称"]=DATA["分项名称"].fillna(df_list[j])
    df_empty=df_empty.append(DATA,ignore_index=True)#输出处理后的结果

#长表转为宽表,存在缺失值,不能保证时间序列的完整性
df2=df_empty.pivot_table(index=["时间"],columns="分项名称",values="用电量").round(decimals=2).reset_index()

#可以如下处理,保证时间序列完整,此处固定显示顺序,参见问题一
L_TYPE_day=list(df_empty.分项名称.unique())
df2=pd.DataFrame(index)
for i in range(len(L_TYPE_day)):
    df_empty_day=df_empty[df_empty.分项名称==L_TYPE_day[i]]
    df2[L_TYPE_day[i]]=list(df_empty_day["用电量"])

存在NaN值如何保证完整序列,数据结构如下

drb070drb072

Q4、数据运算存在NaN如何应对

需求:pandas处理多列相减,实际某些元素本身为空值,如何碰到一个单元格元素为空就忽略了不计算,一般怎么解决!

#构造问题数据源
import pandas as pd
import numpy as np
from collections import Counter
a = Counter(A=1, B=2,C=1,D=2,E=1)

b=["1月","1月","2月","1月","1月","2月","1月"]

c1 =[70,80,40,50,60,90,70]
c2 =[30,40,20,15,30,30,40]
c3 =[20,20,10,20,10,20,10]
c4 =[10,10,5,10,np.nan,20,np.nan]
c5 =[10,5,5,np.nan,10,20,15]

df=pd.DataFrame({"建筑名称":list(a.elements()),"月份":b,"电耗量":c1,"照明用电":c2,"空调用电":c3,"动力用电":c4,"特殊用电":c5})
display(df)
drb0072
#如果这样操作,发现所求列为空值,不是我想要的结果
df["照明用电"]=df["电耗量"]-df["空调用电"]-df["动力用电"]-df["特殊用电"]

drb00072

应该如何处理?
#将dataframe数据转化为二维数组,这时候我们可以利用强大的np模块进行数值计算啦!
arr = df[[i for i in list(df.columns[2:]) if i in(["动力用电", "特殊用电", "空调用电"]) ]].values

df["分项之和"] = np.nansum(arr, axis=1)  

df["照明用电"] = df.apply(lambda x: x["电耗量"] - x["分项之和"], axis=1)

df.drop(columns=["分项之和"])

drb000072

Q5、如何对数据框进行任意行列增、删、改、查操作

df1=df.copy()  #复制一下
# 增操作
#普通索引,直接传入行或列
# 在第0行添加新行
df1.loc[0] = ["F","1月",100,50,30,10,10] 
# 在第0列处添加新列
df1.insert(0, '建筑编码',[1,2,2,3,4,4,5]) 

df1.loc[:,"new"] = np.arange(7) 
df1["new1"]=np.arange(7)
# 在末尾添加列
#或利用字典赋值操作
_dict={"A":1,"B":2,"C":3,"D":4,"E":5,"F":6}
df1["建筑编码1"]=df1["建筑名称"].map(_dict)
#建立字典from collections import defaultdict
#一个个添加,dict_1=defaultdict(lambda:"N/A"),key不存在时,返回一个默认值dict_1[7]="G"
#以列表形式存放元组中,用dict()转换
test_dict=([8,"H"],[9,"I"])
dict_1=dict(test_dict)
#键值对
dict_1=df1.drop_duplicates(['建筑编码']).set_index("建筑编码")["建筑名称"]
#字典的keys()、values()、items()方法
# keys()用来获取字典内的所有键
#values()用来获取字典内所有值
#items()用来得到一组组键值对

# df1.append(df2) # 往末尾添加dataframe
# pd.concat([df1, df2, df3]) # 往末尾添加多个dataframe
# pd.concat([df1, df2, df3], axis = 1) # 往末尾添加多个dataframe

# # 按照关键字合并
# result = pd.merge(df1, df2, on='cities')
# result2 = pd.merge(df1, df2, on='cities', how='outer') 
df1

drb71

# 删
df3=df1.copy()
del df3['new1'] # 删除列
df3=df3.drop(['new', '建筑编码1'], axis = 1)  # 删除多列

df3=df3.drop([8, 9, 10])  # 删除多列

df3=df3.dropna() # 删除带有Nan的行

df3=df3.dropna(axis = 1, how = 'all') # 删除全为Nan的列

df3=df3.dropna(axis = 1, how = 'any') # 删除带有Nan的列

df3=df3.dropna(axis = 0, how = 'all') # 删除全为Nan的行

df3=df3.dropna(axis = 0, how = 'any') # 删除带有Nan的行 默认选项为此

drb071

# 改
df4=df1.copy()
df4
#切片索引,传入行或列的位置区间
df4.iloc[:,5]= np.arange(7)

# # 元素赋值修改
df4.loc[0, '电耗量'] = 900

df4.iloc[0, 2] = "3月"

# df.set_index("建筑名称")
#改列明和索引名
df4 =df4.rename(columns={"照明用电":"照明插座用电"},index={1:8})

df4.fillna(value = 1) # 用1填充缺失值

# 列赋值

df4['year'] = 2020

val = pd.Series(["type7","type2","type2","type3","type4","type4","type5"]) 

df4['建筑类型'] =val   #注意索引不能修改,否则修改行会缺失

# df4['建筑类型'] = ["type7","type2","type2","type3","type4","type4","type5"]  

drb0071

# 查
df5=df1.copy()
df5.index # RangeIndex
df5.columns # Index
df5.values # ndarray

# 元素查找
df5_1= df5.loc[0,'建筑名称'] # 数据是什么类型,xx就是什么类型
# df5_1 = df5.loc[[0],['建筑名称']] # DataFrame类型
# # 行查找 
# df5_2 =df5.loc[0:2] # DataFrame类型012共3行
# df5_2=df5.iloc[0:2] # DataFrame类型 01共1行
df5_2= df5[0:3] # DataFrame类型 前三行

# 列查找
df5_3= df5.loc[:, '建筑编码'] # Series 列查找
df5_3 = df5.loc[:, ['建筑编码', '建筑名称']] # DataFrame类型 多列查找
df5_3 =df5.iloc[:, 0:2] # DataFrame类型 01列

df5_4= df5['建筑名称'] # Series类型

df5_4= df5.建筑名称 # Series类型 同上

df5_5 = df5[['建筑编码1', '建筑名称']] # DataFrame类型 按照新列序

df5_6= df5.filter(regex = '建筑编码1|建筑名称') # DataFrame类型 按照原列序

df5_7=df5[df5.电耗量 > 80]# 选择df5.电耗量中>80的行

# df5[df5.建筑名称.isin(['B', 'C'])] #DataFrame 条件查找

# df5[['建筑编码1', '建筑名称']][0:3] # DataFrame类型 

# # 块查找

df5_8= df5.iloc[0:2, 0:2] # DataFrame类型

#条件查找
# # 条件查找

df5_9=df5.动力用电.notnull() # Series类型 true与false的一列

# df5_9 df5['动力用电'].notnull() # Series 同上

df5_10= df5[df5.动力用电.notnull()] # DataFrame类型 按照year非空选择之后的结果

df5_11= df5[df5.动力用电.notnull()].values # ndarray类型 

df5_12= df5[df5.建筑名称== "D"][df5.月份 == '1月'] # DataFrame

#pandas库中使用.where()函数
# df5_13=df5.where((df5.月份=="1月")&(df5.动力用电>5)).dropna(axis=0)
# 或pandas库中的query()函数
df=df[df.建筑名称=="D"].query(("电耗量>60"))
#使用Numpy的内置where()函数,np.where(condition, value if condition is true, value if condition is false)
df['是否>30'] = np.where(df['照明用电']> 30, True, False)
# 再将样本筛选出
df= df[df['照明用电'] == True]

Q6:如何对字段打标签

#一般情况下,根据值大小,将样本数据划分出不同的等级
方法一:使用一个名为np.select()的函数,给它提供两个参数:一个条件,另一个对应的等级列表。
conditions = [
    (df['负载率'] <=0.3),
    (df['负载率'] > 0.3) & (df['负载率'] <= 0.5),
    (df['负载率'] > 0.5) & (df['负载率'] <= 0.75),
    (df['负载率'] <1)]
values = ['(0-0.3]', '(0.3-0.5]', '(0.5-0.75]', '(0.75-1]']
df['标签'] = np.select(conditions, values)
#统计支路NAME的标签处于(0.75-1]区间情况
df[(df['标签'] == '(0.75-1]')['NAME'].value_counts(normalize=True)

方法二:
bins=[0,0.3,0.5,0.75,1]
df["标签"]=pd.cut(df["负载率"],bins)

方法三:自定义打标签,参加下面推文自定义分类打标签函数

Python自定义分类打标签函数

阅读本文大概约5分钟

直接进入主题………..

1、演示数据表头
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
df=pd.read_excel(r"C:\Users\CQ375\Desktop\test\data.xls")

drb00071

2、用修正z得分检测离群点
data=list(filter(lambda x:x>0,list(df.iloc[:,2])))
import statistics
import itertools
#定义absdev()映射。将使用给定的中位数或计算样本的实际中位数,然后返回一个生成器,提供所有样本与中位数的绝对偏差。
def absdev(data,median=None):
    if median is None:
         median=statistics.median(data)
    return (abs(x-median) for x in data)

#定义median_absdev()函数。将查找绝对偏差值序列的中位数,也将计算用于检测异常的MAD。
def median_absdev(data,median=None):
    if median is None:
        median=statistics.median(data)
    return statistics.median(absdev(data,median=median))

#使用filter()函数,需要一个判定函数,为每一个原始值创建true或False
def outlier(mad,median_x,x):
    return 0.6745*(x-median_x)/mad>=3.5

def pass_outliers2(data):
    population_median=statistics.median(data)
    mad=median_absdev(data,population_median)
    return  (x for x in data if outlier(mad,population_median,x))

list(pass_outliers2(data))

#过滤可能异常值,得到分析数据集
df1=df[df.指标>0]
df2=df1[~df1["指标"].isin(list(pass_outliers2(data)))].reset_index()
df2
3、定义分类标签函数
import numpy as np
from pandas import Series,DataFrame
#查看类型
types=list(df.建筑类型.unique())
# 档次划分(低,中,高,偏高),可对以上做直方图,根据业务情况定义区间划分  
# 类型1
bins1=[0,40,100,160,np.inf]
# 类型3
bins2=[0,30,150,200,np.inf]
# 类型2
bins3=[0,100,200,300,np.inf]

bins_1=[bins1,bins2,bins3]

building_types=['类型1','类型2','类型3']

#分类打标签函数
def func(x): 
    for i in range(len(list(df2.建筑类型))):
        index=building_types.index(df2.loc[i,"建筑类型"])
        if x<bins_1[index][1]:
            return "低"
        elif (x<bins_1[index][2])&(x>=bins_1[index][1]):
            return "中"
        elif (x<bins_1[index][3])&(x>=bins_1[index][2]):
            return "高"
        else:
            return "偏高"

df2["标签"]=df2["指标"].astype("int").map(func)
df2

drb000071

4、查看各类型标签频数分布
for i in range(len(bins_1)):
    plt.figure(figsize = (10, 6))
    plt.rcParams["font.sans-serif"]='SimHei'
    plt.rcParams['axes.unicode_minus']=False
    %config InlineBackend.figure_format='svg'
    df_1=df2[df2["建筑类型"]==building_types[i]]
    energe=list(df_1.指标)
    bins=bins_1[i]  #范围
    labels=["低","中","高","偏高"]
    groups=pd.cut(energe,bins=bins,labels=labels)
    data=groups.value_counts()
    df1=DataFrame(data,columns=["数量"])
    plt.subplot(1,1,1)
    x=labels
    y=df1["数量"].values
    plt.bar(x,y,width=0.5,align="center")
    plt.title("{0}建筑某指标分组".format(building_types[i]),loc="center")
    for a,b in zip(x,y):   
         plt.text(a,b,b,ha="center",va="bottom",fontsize=12)
    plt.ylabel('数量')
    plt.show()

drb70

每日更新Python小例子,实用而不枯燥,每日进步一点点,一起成长,共同进步。全栈技术:python基础、数据分析、数据库、web开发、机器学习、小例子、项目开发案例demo等。

转载请注明:XAMPP中文组官网 » Python数据分析实战之技巧大全