数据集的重塑和透视
该文章内容为《Pandas数据分析实战》的学习笔记
导入需要的包
import pandas as pd
宽数据和窄数据
宽数据集和窄数据集的名称反应了数据集的扩展方向
-
宽数据集:数据越多,数据集越宽
-
窄数据集:数据越多,数据越长
由DataFrame创建数据透视表
pd.read_csv("pandas-in-action-master/chapter_08_reshaping_and_pivoting/sales_by_employee.csv").head()
# 将Date列中的字符串转换为datetime导入
sales = pd.read_csv("pandas-in-action-master/chapter_08_reshaping_and_pivoting/sales_by_employee.csv"
, parse_dates = ["Date"])
sales
导入数据之后,将介绍一下如何使用数据透视表来聚合数据集内的数据
pivot_table
方法
创建数据透视表:
-
选择要做聚合操作的列
-
选择要应用于该列的聚合操作
-
选择用于数据集分组的列
-
确定是否将"分组"放置在行轴、列轴或两个轴上
使用pivot_table
方法。该方法的index参数用于设定数据透视表的索引标签。Pandas将使用该列中的唯一真值对结果进行分组
sales.pivot_table(index = "Date", values=["Revenue", "Expenses"], aggfunc="mean")
其中values参数为选择需要操作的列,必须是数字列;aggfunc参数为需要执行的操作。比如说还可以:
sales.pivot_table(index = "Date", values="Revenue", aggfunc="sum")
对索引级别进行堆叠和取消堆叠
根据员工姓名和日期来调整sales数据集,并显示收入值
by_name_and_date = sales.pivot_table(
index = "Name",
columns = "Date",
values = "Revenue",
aggfunc = "sum"
)
by_name_and_date
通过stack
方法,可以将索引级别从列轴移到行轴。由于转换之后只有一列数据,此时数据将会被转换为Series
by_name_and_date.stack()
注意在DataFrame中为了结构完整使用NaN来保留单元格,这里转换为Series了就不需要了,所有就没有NaN了
unstack
可以将索引从行轴移动到列轴
融合数据集
video_game_sales = pd.read_csv("pandas-in-action-master/chapter_08_reshaping_and_pivoting/video_game_sales.csv")
video_game_sales.head()
我们可以观察到,表中存储的数据是销售额,而列名确实地区,所以如果我们想要增加销售额的数据,我们需要横向扩展,所以这是一个宽数据集。也就是说如果列名为Sale则这是一个窄数据集
Pandas使用melt
方法来分解一个DataFrame(数据分解是将一个宽数据集转换为一个窄数据集的过程)。该方法接受两个主要参数:
-
id_vars
参数识别标识符,宽数据集在该列聚合 -
value_vars
参数接受一(多)列,它的值将分解并存储在一个新列中
video_game_sales.melt(
id_vars = "Name",
value_vars = ["NA", "EU", "JP", "Other"]
)
将var_name和value_name来自定义分解DataFrame的列名
video_game_sales.melt(
id_vars = "Name",
value_vars = ["NA", "EU", "JP", "Other"],
var_name = "Region",
value_name = "Sales"
)
窄数据比宽数据更容易聚合,我们可以使用
pivot_table
方法用几行代码完成这个任务
展开值列表
recipes = pd.read_csv("pandas-in-action-master/chapter_08_reshaping_and_pivoting/recipes.csv")
recipes.head()
我们可以看到Ingredients列中的元素由多个元素组成,如果我们像下面这样做,会得到一个我们不希望看到的结果
recipes["Ingredients"] = recipes["Ingredients"].str.split(",")
recipes
如果我们想要将每个列表的值分布在多行,我们可以使用explode
方法为Series中的每个列元素创建一个单独的行
recipes.explode("Ingredients")
代码挑战
本节中要用到两个数据集,其中 used_cars.csv
数据集是分类网站 Craigslist 上待售二手车的列表,每行包括汽车的制造商、生产年份、燃料类型、变速器类型和价格的相关信息
minimum_wage.csv
数据集是美国最低工资的集合。该数据集有一个州列和多个代表具体年份的列
本节需要解决的问题如下:
- 对汽车的价格进行汇总,在行轴上按燃料类型对结果进行分组。
- 汇总汽车的数量。在索引轴上按制造商对结果进行分组,在列轴上按变速器类型对结果进行分组,显示行和列的小计。
- 计算汽车价格的平均值。在索引轴上按年份和燃料类型对结果进行分组,在列轴上按变速器类型对结果进行分组。
- 对于问题(3)得到的 DataFrame,将变速器类型从列轴移到行轴。
- 将
min_wage
从宽格式转换为窄格式。换句话说,将原来 2010 年到 2017 年的 8 列转换成一列。
解决方案
cars = pd.read_csv("pandas-in-action-master/chapter_08_reshaping_and_pivoting/used_cars.csv")
min_wage = pd.read_csv("pandas-in-action-master/chapter_08_reshaping_and_pivoting/minimum_wage.csv")
cars
# 1
cars.pivot_table(values = "Price", index = "Fuel", aggfunc = "sum")
# 2
cars.pivot_table(values = "Price", index = "Manufacturer", columns = "Transmission", aggfunc = "count", margins = True)
# 3
cars.pivot_table(
values = "Price",
index = ["Year", "Fuel"],
columns = "Transmission",
aggfunc = "mean"
)
# 4
report = cars.pivot_table(
values = "Price",
index = ["Year", "Fuel"],
columns = "Transmission",
aggfunc = "mean"
)
report.stack()
# 5
min_wage.melt(id_vars = "State", value_vars = ["2010", "2011", "2012", "2013", "2014", "2015", "2016", "2017"])
关注公众号小辛到处学,发送1,获取文中的数据资源