【Python】数据分析.pandas.数据的分组、聚合

网友投稿 309 2022-08-24

【Python】数据分析.pandas.数据的分组、聚合

文章目录

​​数据分析.pandas.数据的分组、聚合​​

​​一、分组---groupby()​​​​二、DataFrameGroupBy对象​​​​三、聚合​​

​​3.1 简单直接聚合​​​​3.2 使用agg方法聚合数据​​

​​3.2.1 自定义函数​​​​3.2.2 实现对分组后的数据进行统计​​

​​3.3 使用apply方法聚合数据​​​​3.4 使用transform方法聚合数据​​

​​四、星巴克案例扩展​​​​五、911紧急拨号案例扩展​​

数据分析.pandas.数据的分组、聚合

对数据进行整体性的聚合运算以及分组操作也是数据分析的重要内容。 通过数据的聚合与分组,我们能更容易的发现隐藏在数据中的规律。下面我们根据星巴克的案例来进行学习~

一、分组—groupby()

这里所用到的分组方法与数据库里所学到的分组基本一样,可以按照某一列或者是某几列进行分组。

以下是groupby()函数的源码:

当然,它的底层还是有另一层源码的,这里不再深入,主要就是详细的如何分组,大家可以去看一下~但通过这上面的两端,我们不难发现groupby()方法返回的是一个Series类型的值,下面我们会解释。

下面结合案例来进行解释​​​基本需求:得到每个国家的星巴克店的数量​​

​​第一步:分组​​

import numpy as npimport pandas as pdfile_path = "starbucks/directory.csv"df = pd.read_csv(file_path)# print(df.head(1))# print(df.info())#按照国家来分类grouped = df.groupby(by="Country")print(grouped)#这里的grouped得到的是一个DataFrameGroupBy对象,可迭代

​​返回顶部​​

二、DataFrameGroupBy对象

经过groupby()分组后得到的是一个DataFrameGroupBy对象,不可以直接显示具体数据,只能显示出在内存中的内存地址。

对于该对象具体数据,我们可以通过迭代来进行查看:

# 可以进行遍历for i in grouped: print(i) print("*"*100) #返回一个两个元素的元组,第一个是国家(Country),第二个是该国家下的所有数据,类型是dataframe# ('AE', Brand Store Number ... Longitude Latitude# 1 Starbucks 22331-212325 ... 55.47 25.42# 2 Starbucks 47089-256771 ... 55.47 25.39# 3 Starbucks 22126-218024 ... 54.38 24.48# 4 Starbucks 17127-178586 ... 54.54 24.51# 5 Starbucks 17688-182164 ... 54.49 24.40# .. ... ... ... ... ...# 140 Starbucks 34253-62541 ... 55.38 25.33# 141 Starbucks 1359-138434 ... 55.38 25.32# 142 Starbucks 34259-54260 ... 55.37 25.30# 143 Starbucks 34217-27108 ... 55.48 25.30# 144 Starbucks 22697-223524 ... 55.54 25.53# [144 rows x 13 columns])

以上是按照国家分组后每个国家的星巴克情况(由于数据较大,只截取了国家为‘AE’的,中间数据也有部分省略)

我们可以看到,该对象返回一个两个元素的元组,第一个是国家(Country),第二个是该国家下的所有数据,类型是dataframe。

​​返回顶部​​

三、聚合

3.1 简单直接聚合

所谓聚合,就是执行多个值变成一个值的操作。而在Python中,就是将一个矢量(数组)变成标量。在Python中主要有如图所示的几中聚合方法。

print('订单详情表分组后前5组的均值为:\n',detailgroup.mean().head())#订单详情表分组后前5组的均值为: counts amountsorder_id 1002 1.0000 32.0001003 1.2500 30.1251004 1.0625 43.8751008 1.0000 63.0001011 1.0000 57.700print('订单详情表分组后前5组的标准差为:\n',detailgroup.std().head())#订单详情表分组后前5组的标准差为: counts amountsorder_id 1002 0.00000 16.0000001003 0.46291 21.3838221004 0.25000 31.1958861008 0.00000 64.8806601011 0.00000 50.077828print('订单详情表分组后前5组的每组大小:\n',detailgroup.size().head())#订单详情表分组后前5组的每组大小: order_id1002 71003 81004 161008 51011 10dtype:

​​第二步:调用聚合函数计算​​

# 可以调用聚合函数print(grouped.count()) #会将每一列按照国家来进行进行统计# Brand Store Number Store Name ... Timezone Longitude Latitude# Country ...# AD 1 1 1 ... 1 1 1# AE 144 144 144 ... 144 144 144# AR 108 108 108 ... 108 108 108# AT 18 18 18 ... 18 18 18# AU 22 22 22 ... 22 22 22# ... ... ... ... ... ... ...# TT 3 3 3 ... 3 3 3# TW 394 394 394 ... 394 394 394# US 13608 13608 13608 ... 13608 13608 13608# VN 25 25 25 ... 25 25 25# ZA 3 3 3 ... 3 3 3# [73 rows x 12 columns]print(grouped["Brand"].count()) #也可以对其中的所需要的一列进行统计# AD 1# AE 144# AR 108# AT 18# AU 22# ...# TT 3# TW 394# US 13608# VN 25# ZA 3# Name: Brand, Length: 73, dtype: int64

​​返回顶部​​

3.2 使用agg方法聚合数据

agg、aggregate方法都可以对每个分组应用某个函数,也可以直接对dataframe进行函数操作。 实际操作过程中两种方法作用相同

DataFrame.agg(func,axis=0,*args,**kwargs)DataFrame.aggregate(func,axis=0,*args,**kwargs)

可以使用agg函数求出对应的统计量;也可以根据要求,对于某个字段做单独的处理,例如对counts字段进行求和,对amounts字段进行求均值,但此时需要以字典的形式,将字段名作为key,函数作为value传入;同时还可以对不同字段的不同数目进行统计,当不唯一时只需要将字典对应的value转换为列表即可。

3.2.1 自定义函数

注意在agg中可以使用numpy库中的函数(np.mean、np.median、np.prod、np.sum、np.std、np.var),但是在自定义函数中使用此类函数时,若计算的是单个序列,则无法得到预期结果,需为多列数据同时计算。

​​返回顶部​​

3.2.2 实现对分组后的数据进行统计

​​返回顶部​​

3.3 使用apply方法聚合数据

与agg方法相比较,agg方法传入的参数只能够作用于整个DataFrame或者Series,并且apply方法无法像agg方法一样对不同的字段应用不同的函数来获取不同的结果。

DataFrame.apply(func,axis=0,broadcast=False,raw=False,reduce=None,arg=(),**kwds)

参数名称

说明

func

接收functions。代表应用于每行或每列的函数

axis

接收0或1,代表操作的轴向

broadcast

接收boolean,代表是否进行广播,默认为False

raw

接收boolean,表示是否直接将ndarray对象传递给参数,默认为False

reduce

接收boolean或None,表示返回的格式

​​返回顶部​​

3.4 使用transform方法聚合数据

transform方法能够对整个DataFrame的所有元素进行操作

在这里介绍一下使用lambda表达式定义函数: 1.lambda表达式定义函数是比较特殊一种函数定义方式,该函数是中匿名函数,也就是该函数没有函数名。使用该中函数会返回一个值,调用时直接使用该函数的值。 2.在lambda表达式中不能够使用print语句 3.在lambda表达式中不能够使用其他语句

​​返回顶部​​

groupby对象的函数 ----- apply 在不同分组上应用‘func’函数,然后将结果组合起来。 ----- agg/aggregate 聚合(agg/aggregate)在特定轴(列)上应用一或多个操作(函数) ----- transform 调用函数在每个分组上产生一个与原df相同索引的DataFrame,整体返回与原来对象拥有相同索引且 已填充了转换后的值的DataFrame

​​返回顶部​​

四、星巴克案例扩展

​​需求:比较中国和美国的星巴克店数​​

在上面的基础上,我们来获取中国和美国的星巴克店的数量country_count = grouped["Brand"].count()print(country_count["US"]) //美国print(country_count["CN"]) //中国

​​​需求:具体了解到中国的每一个省份的星巴克店的数量​​

china_data = df[df["Country"]=="CN"] #注意这里在查找时是作为条件,应当为bool类型grouped = china_data.groupby(by="State/Province").count()["Brand"]print(grouped) #数字代表中国的省份编码# State/Province# 11 236# 12 58# 13 24# 14 8# 15 8# 21 57# 22 13# 23 16# 31 551# 32 354# 33 315# 34 26# 35 75# 36 13# 37 75# 41 21# 42 76# 43 35# 44 333# 45 21# 46 16# 50 41# 51 104# 52 9# 53 24# 61 42# 62 3# 63 3# 64 2# 91 162# 92 13# Name: Brand, dtype: int64

​​需求:按照多个条件进行分组,同时按照国家和省份分组​​​这样会显示出每个国家的每个地区的数量情况,更加直观~

#同时按照国家和省份分组,就会有两个索引,返回的是Seriesgrouped = df["Brand"].groupby(by=[df["Country"],df["State/Province"]]).count()print(grouped)# Country State/Province# AD 7 1# AE AJ 2# AZ 48# DU 82# FU 2# ..# US WV 25# WY 23# VN HN 6# SG 19# ZA GT 3# Name: Brand, Length: 545, dtype: int64

补充:若想返回的值是DataFrame类型,可以再案列名查找时多添加一个"[]"

grouped1 = df[["Brand"]].groupby(by=[df["Country"],df["State/Province"]]).count()print(grouped1,type(grouped1))print("*"*100)grouped2 = df.groupby(by=[df["Country"],df["State/Province"]])[["Brand"]].count()print(grouped2,type(grouped2))print("*"*100)grouped3 = df.groupby(by=[df["Country"],df["State/Province"]]).count()[["Brand"]]print(grouped3,type(grouped3))#以上的三种方式结果均为下表# Brand# Country State/Province# AD 7 1# AE AJ 2# AZ 48# DU 82# FU 2# ...# US WV 25# WY 23# VN HN 6# SG 19# ZA GT 3# [545 rows x 1 columns]

​​需求:使用matplotlib呈现出店铺总数排名前十的国家​​

#使用matplotlib呈现出店铺总数排名前十的国家import numpy as npimport pandas as pdfrom matplotlib import pyplot as pltfrom matplotlib import font_manager#设置字体#设置字体my_font=font_manager.FontProperties(fname="C:\Windows\Fonts\STXINGKA.TTF",size=18)#准备数据file_path = "starbucks/directory.csv"df = pd.read_csv(file_path)data = df.groupby(by="Country").count()["Brand"].sort_values(ascending=False)[:10]x = data.indexy = data.values#设置图形大小plt.figure(figsize=(20,8),dpi=80)#绘图plt.bar(range(len(x)),y)plt.xticks(range(len(x)),x)#添加信息plt.xlabel("国家",fontproperties=my_font)plt.ylabel("该国星巴克店铺数",fontproperties=my_font)plt.title("星巴克店铺总数排名前十的国家",fontproperties=my_font)#展示plt.show()

​​​需求:中国星巴克数排名前25的城市店铺总数​​

import numpy as npimport pandas as pdfrom matplotlib import pyplot as pltfrom matplotlib import font_manager#设置字体#设置字体my_font=font_manager.FontProperties(fname="C:\Windows\Fonts\STXINGKA.TTF",size=18)#准备数据file_path = "starbucks/directory.csv"df = pd.read_csv(file_path)df = df[df["Country"]=="CN"]data = df.groupby(by="City").count()["Brand"].sort_values(ascending=False)[:25]x = data.indexy = data.values#设置图形大小plt.figure(figsize=(20,8),dpi=80)#绘图plt.bar(range(len(x)),y,width=0.3)plt.xticks(range(len(x)),x,fontproperties=my_font)#添加信息plt.xlabel("城市",fontproperties=my_font)plt.ylabel("该城市星巴克店铺数",fontproperties=my_font)plt.title("中国星巴数排名前25的城市克店铺总",fontproperties=my_font)#绘制网格plt.grid()#展示plt.show()

通过绘制图形显示直接明了,但是这里还有不足之处,就是x轴太密集,不便于观察,接下来我们进行操作,使用横向的条形图。(​​关于条形图的绘制可参考本人之前的文章​​)

x = data.indexy = data.values#设置图形大小plt.figure(figsize=(20,8),dpi=80)#绘图plt.barh(range(len(x)),y,height=0.3)plt.yticks(range(len(x)),x,fontproperties=my_font)#添加信息plt.ylabel("城市",fontproperties=my_font)plt.xlabel("该城市星巴克店铺数",fontproperties=my_font)plt.title("中国星巴数排名前25的城市克店铺总数",fontproperties=my_font)

​​返回顶部​​

五、911紧急拨号案例扩展

​​需求:计算911紧急拨号不同类型的次数​​​

根据已经获取到的数据,我们可以从中发现,具体的分类是在title列下字符串的前半段。至此,我们可以明确目标:

1.获取分号之前的字符串 ----- 按照“:”切割 2.统计 ----- sum()、count()方法一:在原有数据基础上,直接分类统计 思路:首先,按照“:”分割字符串并将结果转化为list;接着,遍历list,将第i个元素中的第一个子元素取出,就得到了每个元素的分类,再用set()去重,最后转为list得到所有分类类型的列表;然后,我们就该统计,按照常理,既然有了所有分类,之前又得到了分割后具有分类的列表,那么直接去遍历,对应分类计数即可。在执行过程中会有两种方式:1.逐行遍历赋值 每一行都去和分类比较,在对应的分类下计数 这种方式理论可行,但在实际的操作执行过程中很耗时间。2.分类赋值 按照找出的分类,按照分类赋值 其中涉及contains()函数,它可以迅速返回目标的布尔值,借助布尔值实现直接分类赋值。 在统计时我们还要创建一组全为零的dataframe,遍历计数是需要用到的。

import numpy as npimport pandas as pdfrom matplotlib import pyplot as pltfrom matplotlib import font_manager#设置中文my_font = font_manager.FontProperties(fname="C:\Windows\Fonts\STXINGKA.TTF",size=18)#读取csv文件file_path = "911-calls/911.csv"df = pd.read_csv(file_path)#获取分类temp_list = df["title"].str.split(":").tolist()#分类在title字段中,这里将以:切分字符串并转化为list,每个元素类似于['EMS', ' SUBJECT IN PAIN']cate_list = list(set(i[0] for i in temp_list))#先遍历list,将第i个元素中的第一个子元素取出,就得到了每个元素的分类,再用set()去重,最后转为list得到分类的列表print(cate_list) #['Traffic', 'Fire', 'EMS']#构造全为0的数组zeros_df = pd.DataFrame(np.zeros((df.shape[0],len(cate_list))),columns=cate_list)#赋值#法一,遍历分类,为该分类的赋值for cate in cate_list: zeros_df[cate][df["title"].str.contains(cate)] = 1print(zeros_df)#法二,逐行遍历赋值# for i in range(df.shape[0]):# zeros_df.loc[i,temp_list[i][0]] = 1# print(zeros_df)sum_ret = zeros_df.sum(axis=0)print(sum_ret)

方法二:在原有数据基础上,再设置一列为分类,进行对该列的统计 思路:首先,按照“:”分割字符串并将结果转化为list;接着,遍历list,将第i个元素中的第一个子元素取出,定义为新的一列;最后,直接分组统计分类一列即可。

import numpy as npimport pandas as pdfrom matplotlib import pyplot as pltfrom matplotlib import font_manager#设置中文my_font = font_manager.FontProperties(fname="C:\Windows\Fonts\STXINGKA.TTF",size=18)#读取csv文件file_path = "911-calls/911.csv"df = pd.read_csv(file_path)#获取分类temp_list = df["title"].str.split(":").tolist()#分类在title字段中,这里将以:切分字符串并转化为list,每个元素类似于['EMS', ' SUBJECT IN PAIN']cate_list = [i[0] for i in temp_list]#先遍历list,获取出第i个元素中的第一个子元素cate_df = pd.DataFrame(np.array(cate_list).reshape((df.shape[0]),1))df["cate"] = cate_df #添加新的一列分类print(df.groupby(by="cate").count()["title"])

​​返回顶部​​

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:数字化营销是什么?应该如何正确投放?(什么是数字化营销方式)
下一篇:【Spring Cloud】Nacos注册中心
相关文章

 发表评论

暂时没有评论,来抢沙发吧~