【python数据分析基础】—pandas透视表和交叉表


前言

透视表是excel和其他数据分析软件中一种常见的数据汇总工具。它是根据一个或多个键对数据进行聚合,并根据行和列上的分组键将数据分配到各个矩形区域中。


一、pivot_table 透视表

pivot_table()默认显示指定索引列和所有数值列。

语法:

pivot_table(data: ‘DataFrame’, values=None, index=None, columns=None, aggfunc: ‘AggFuncType’ = ‘mean’, fill_value=None, margins: ‘bool’ = False, dropna: ‘bool’ = True, margins_name: ‘str’ = ‘All’, observed: ‘bool’ = False, sort: ‘bool’ = True)

参数解析:

  • data:dataframe数据框。
  • value:需要聚合的列的名称,可选。默认聚合所有数值列。
  • index:用于分组的列名或其他分组键,出现在结果透视表的行。
  • columns:用于分组的列名或其他分组键,出现在结果透视表的列。
  • aggfunc:聚合函数或函数列表,默认为"mean",可以是任何对groupby有效的函数。
  • fill_value:用于替换结果表中的缺失值。
  • margins:添加行/列小计和总计,默认为False。
  • dropna:不聚合所有值都为NA的列,默认为True。
  • margins_name:如果margins=True,设置添加行/列小计和总计的名称,默认为"All"。

举例:

以小费数据集为例,数据情况如下:

import pandas as pd
tips=pd.read_csv('F:\\pydata-book-2nd-edition\\examples\\tips.csv')
tips["tip_pct"]=tips["tip"]/tips["total_bill"] #添加一列小费比例tip_pct
tips.head(10)

在这里插入图片描述

tips.shape # (244, 8)
tips.columns

在这里插入图片描述

参数index:根据sex和smoker计算分组平均数。

#pivot_table的默认聚合类型:平均数
tips.pivot_table(index=['sex ','smoker'])

在这里插入图片描述

参数values和columns:只想聚合"tip_pct"和"size",根据"sex","day"分组,将"smoker"放到列上,"day"放到行上。

tips.pivot_table(['tip_pct','size'],index=['sex ','day'],columns='smoker')

在这里插入图片描述

参数margins:margins=True 添加分项小计,这将会添加标签为all的行和列,其值对应单个等级中所有数据的分组统计,all值为平均值。

tips.pivot_table(['tip_pct','size'],index=['sex ','day'],columns='smoker',margins=True)

在这里插入图片描述

参数aggfunc:要使用其他的聚合函数,将其传给aggfunc即可,用len或count可以得到有关分组大小的交叉表。

tips.pivot_table('tip_pct',index=['sex ','smoker'],columns='day',aggfunc=len,margins=True)

在这里插入图片描述

参数fill_value:fill_value可以填补空值(NA)

tips.pivot_table('size',index=['time','sex ','smoker'],columns='day',aggfunc='sum',fill_value=0)

在这里插入图片描述


二、crosstab 交叉表

交叉表作为一种特殊的透视表,用于计算分组频率的特殊透视表。

语法:

crosstab(index, columns, values=None, rownames=None, colnames=None, aggfunc=None, margins: ‘bool’ = False, margins_name: ‘str’ = ‘All’, dropna: ‘bool’ = True, normalize=False)

参数解析:

  • index:接收string、数组、Series或数组list,表示行索引键,无默认。
  • columns:接收string、数组、Series或数组list,表示列索引键,无默认。
  • values:接收array,表示聚合数据,置信为None。
  • rownames:表示行分组键名,无默认。
  • colnames:表示列分组键名,无默认。
  • aggfunc:接收function,表示聚合函数,默认为None。
  • margins:布尔值,默认为True。表示汇总(total)功能的开关,设置为True后,结果集中会出现名为"ALL"的行和列。
  • margins_name:设置总计行(列)的名称(默认名称是“All”)
  • dropna:布尔值,表示是否对值进行标准化,默认为False。
  • normalize:布尔值,表示是否对值进行标准化,默认为False。

举例:

import numpy as np
data = pd.DataFrame({"Sample":np.arange(10),"Gender":np.random.choice(("Female","Male"),10),"Handedness":np.random.choice(("Right-handed","Left-handed"),10)})
data

在这里插入图片描述

根据性别和用手习惯对这段数据进行统计汇总。

import pandas as pd
pd.crosstab(data["Gender"],data["Handedness"],margins=True)

在这里插入图片描述


三、实际应用

示例1:数据聚合与分组实际应用

数据集情况:

import pandas as pd
fec=pd.read_csv('F:\\pydata-book-2nd-edition\\datasets\\fec\\P00000001-ALL.csv')
fec.shape #(1001731, 16)
fec.columns

在这里插入图片描述

fec.iloc[123456]

在这里插入图片描述

  • 分析1: 获取全部的候选人的名单
uniques_cands=fec.cand_nm.unique()
uniques_cands
uniques_cands[2]

在这里插入图片描述

  • 分析2: 补充党派信息

第一步:利用字典说明党派关系。

parties={'Bachmann, Michelle':'Republican',
         'Romney, Mitt':'Republican', 
         'Obama, Barack':'Democrat',
       "Roemer, Charles E. 'Buddy' III":'Republican',
         'Pawlenty, Timothy':'Republican',
       'Johnson, Gary Earl':'Republican',
         'Paul, Ron':'Republican', 
         'Santorum, Rick':'Republican',
       'Cain, Herman':'Republican', 
         'Gingrich, Newt':'Republican',
       'McCotter, Thaddeus G':'Republican',
       'Huntsman, Jon':'Republican',
         'Perry, Rick':'Republican'}

第二步:通过映射以及series对象的map方法,你可以根据候选人姓名得到一组党派信息,将其添加一个新列。

fec['party']=fec.cand_nm.map(parties)
fec['party'].value_counts()

在这里插入图片描述

数据集中“contb_receipt_amt”既包括退款也包括赞助,因此限定数据集只有正的出资额。

(fec["contb_receipt_amt"]>0).value_counts()

在这里插入图片描述

fec=fec[fec["contb_receipt_amt"]>0]
  • 分析3: 根据职业和雇主统计赞助信息

第一步:根据职业计算出资总额。

fec["contbr_occupation"].value_counts()[:10]

在这里插入图片描述

第二步:对职业信息、雇主信息进行映射。

occ_mapping={'INFORMATION REQUESTED':'NOT PROVIDED','INFORMATION REQUESTED PER BEST EFFORTS':'NOT PROVIDED','INFORMATION REQUESTED(BEST EFFORTS)':'NOT PROVIDED','C.E.O':'CEO'}

#如果没有映射消息则返回x
f=lambda x:occ_mapping.get(x,x)
fec["contbr_occupation"]=fec["contbr_occupation"].map(f)
emp_mapping={'INFORMATION REQUESTED':'NOT PROVIDED','INFORMATION REQUESTED PER BEST EFFORTS':'NOT PROVIDED','SELF':'SELF-EMPLOYED','SELF EMPLOYED':'SELF-EMPLOYED'}

f=lambda x:emp_mapping.get(x,x)
fec["contbr_employer"]=fec["contbr_employer"].map(f)

第三步:根据党派和职业对数据进行聚合,过滤掉总出资额不足200万美元的数据,生成透视表。

by_occupation = pd.pivot_table(fec,values='contb_receipt_amt',index='contbr_occupation',columns='party',aggfunc="sum")

第四步:生成柱状图

over_2mm = by_occupation[by_occupation.sum(1)>2000000]
over_2mm
over_2mm.plot(kind='barh')

在这里插入图片描述

  • 分析4: 总出资额最高的职业和企业

求最大值方法

def get_top_amounts(group,key,n=5):
    totals=group.groupby(key)['contb_receipt_amt'].sum()
    return totals.sort_values(ascending=False)[n:] #根据key对totals进行降序排列

根据职业和雇主进行聚合

fec_mrbo=fec[fec['cand_nm'].isin(['Obama, Barack','Romney, Mitt'])]

grouped=fec_mrbo.groupby('cand_nm')

grouped.apply(get_top_amounts,'contbr_occupation',n=7)#get_top_amounts函数的参数值

在这里插入图片描述

grouped.apply(get_top_amounts,'contbr_employer',n=10)

在这里插入图片描述

  • 分析5: 对出资额分组

第一步:利用cut函数根据出资额大小将数据离散到多个面元中。

bins=np.array([0,10,100,1000,10000,100000,1000000,10000000,100000000])
labels=pd.cut(fec_mrbo.contb_receipt_amt,bins)
labels

在这里插入图片描述

第二步:根据候选人的姓名以及面元标签对数据进行分组。

grouped=fec_mrbo.groupby(['cand_nm',labels])
grouped.size().unstack(0)

在这里插入图片描述

可以看到obama在小额赞助的数量比romney多得多。

第三步:对出资额求和并在面元内规格化,以便图形化显示两位候选人各种赞助额度的比例:

bucket_sums=grouped.contb_receipt_amt.sum().unstack(0)
bucket_sums

在这里插入图片描述

数据按行求频率如下:

normed_sums=bucket_sums.div(bucket_sums.sum(axis=1),axis=0)
normed_sums

在这里插入图片描述

两位候选人收到的各种捐赠额度的总额比例:

normed_sums[:-2].plot(kind='barh',stacked=True) #排除了两具最大的面元。

在这里插入图片描述

  • 分析6: 根据州统计赞助信息

第一步:根据候选人和州对数据进行聚合。

grouped=fec_mrbo.groupby(['cand_nm','contbr_st'])
totals=grouped.contb_receipt_amt.sum().unstack(0).fillna(0)
totals=totals[totals.sum(1)>100000]
totals[:10]

在这里插入图片描述

第二步:对各行除以总赞助额,就会得到各候选人在各州的总赞助额比例。

percent=totals.div(totals.sum(1),axis=0)
percent[:10]

在这里插入图片描述

  • 28
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
pandas 中的交叉透视都是用于数据分析和汇总的工具,但它们在处理数据时有所不同。 交叉可以帮助我们快速计算两个或多个因素之间的频数,而透视则可以帮助我们将数据按照不同的维度进行分组并进行聚合计算。 下面我将分别介绍一下 pandas 中的交叉透视。 ## 交叉 pandas 中的 `crosstab()` 函数可以帮助我们创建交叉。该函数的语法如下: ```python pandas.crosstab(index, columns, values=None, aggfunc=None, margins=False, margins_name='All', dropna=True, normalize=False) ``` 其中: - `index`:用于指定行索引的列或列名。 - `columns`:用于指定列索引的列或列名。 - `values`:用于指定填充交叉的数据列或列名。如果不指定,则默认为计数。 - `aggfunc`:用于指定对数据进行聚合计算的函数。默认为计数。 - `margins`:用于指定是否在交叉中添加行/列合计。默认为 False。 - `margins_name`:用于指定行/列合计的名称。默认为 "All"。 - `dropna`:用于指定是否删除包含缺失值的行/列。默认为 True。 - `normalize`:用于指定是否对交叉进行标准化。 下面是一个示例: ```python import pandas as pd data = { "Gender": ["F", "M", "F", "M", "M", "M", "F", "F", "M", "F"], "Age": [30, 25, 35, 40, 30, 45, 35, 25, 30, 35], "City": ["Beijing", "Shanghai", "Guangzhou", "Shenzhen", "Shanghai", "Beijing", "Shenzhen", "Guangzhou", "Beijing", "Shenzhen"] } df = pd.DataFrame(data) print(df) # 创建交叉 ct = pd.crosstab(df["Gender"], df["City"]) print(ct) ``` 输出结果为: ``` Gender Age City 0 F 30 Beijing 1 M 25 Shanghai 2 F 35 Guangzhou 3 M 40 Shenzhen 4 M 30 Shanghai 5 M 45 Beijing 6 F 35 Shenzhen 7 F 25 Guangzhou 8 M 30 Beijing 9 F 35 Shenzhen City Beijing Guangzhou Shanghai Shenzhen Gender F 1 1 0 2 M 2 0 2 1 ``` 上面的代码首先创建了一个包含 Gender、Age 和 City 三列数据的 DataFrame。然后使用 `crosstab()` 函数创建了一个交叉,用于统计不同性别和城市的人数。 从输出结果可以看出,交叉中的行和列分别对应于原始数据中的 Gender 和 City 列。交叉中的值示对应行和列的交叉处的人数。 ## 透视 pandas 中的 `pivot_table()` 函数可以帮助我们创建透视。该函数的语法如下: ```python pandas.pivot_table(data, values=None, index=None, columns=None, aggfunc='mean', fill_value=None, margins=False, margins_name='All', dropna=True) ``` 其中: - `data`:用于指定要使用的数据集。 - `values`:用于指定要进行聚合计算的数据列或列名。 - `index`:用于指定行索引的列或列名。 - `columns`:用于指定列索引的列或列名。 - `aggfunc`:用于指定对数据进行聚合计算的函数。默认为平均值。 - `fill_value`:用于指定要用于填充缺失值的值。 - `margins`:用于指定是否在透视中添加行/列合计。默认为 False。 - `margins_name`:用于指定行/列合计的名称。默认为 "All"。 - `dropna`:用于指定是否删除包含缺失值的行/列。默认为 True。 下面是一个示例: ```python import pandas as pd data = { "Gender": ["F", "M", "F", "M", "M", "M", "F", "F", "M", "F"], "Age": [30, 25, 35, 40, 30, 45, 35, 25, 30, 35], "City": ["Beijing", "Shanghai", "Guangzhou", "Shenzhen", "Shanghai", "Beijing", "Shenzhen", "Guangzhou", "Beijing", "Shenzhen"] } df = pd.DataFrame(data) print(df) # 创建透视 pt = pd.pivot_table(df, values="Age", index="City", columns="Gender", aggfunc="mean") print(pt) ``` 输出结果为: ``` Gender Age City 0 F 30 Beijing 1 M 25 Shanghai 2 F 35 Guangzhou 3 M 40 Shenzhen 4 M 30 Shanghai 5 M 45 Beijing 6 F 35 Shenzhen 7 F 25 Guangzhou 8 M 30 Beijing 9 F 35 Shenzhen Gender F M City Beijing 32.500000 37.500000 Guangzhou 30.000000 NaN Shanghai NaN 27.500000 Shenzhen 35.000000 40.000000 ``` 上面的代码首先创建了一个包含 Gender、Age 和 City 三列数据的 DataFrame。然后使用 `pivot_table()` 函数创建了一个透视,用于统计不同城市和性别的平均年龄。 从输出结果可以看出,透视中的行和列分别对应于原始数据中的 City 和 Gender 列。透视中的值示对应行和列的交叉处的平均年龄。如果原始数据中没有某一行/列的数据,则透视中对应的单元格会显示为 NaN。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值