本文概述
- 分层索引和熊猫数据框
- 层次结构索引, groupby对象和Split-Apply-Combine
- 日常使用的分层索引
文章图片
这是通过按单个列进行分组来实现的。顺便说一句, 我提到你可能希望按几列进行分组, 在这种情况下, 生成的pandas DataFrame最终会具有多索引或层次结构索引。在本文中, 你将学习什么层次索引, 并查看它们在按数据的几个功能分组时如何产生。你可以在我们的” 用熊猫操作数据框” 课程中找到有关所有这些概念和实践的更多信息。
首先, 什么是层次结构索引?
文章图片
分层索引和熊猫数据框 什么是数据帧的索引?
在介绍层次结构索引之前, 我想让你回顾一下熊猫DataFrame的索引是什么。 DataFrame的索引是一个集合, 由每行的标签组成。让我们来看一个例子。我将首先导入假设的srcmini学生Ellie在srcmini上的活动的综合数据集。这些列是日期, 编程语言以及当天Ellie用该语言完成的练习次数。加载数据:
# Import pandasimport pandas as pd# Load in datadf = pd.read_csv('data/user_ex_python.csv')df
日期 | 语言 | ex_complete | |
---|---|---|---|
0 | 2017-01-01 | python | 6 |
1 | 2017-01-02 | python | 5 |
2 | 2017-01-03 | python | 10 |
# Check out indexdf.index
RangeIndex(start=0, stop=3, step=1)
我们可以使用此索引切出一行df:
# Slice and dice datadf.loc[:1]
日期 | 语言 | ex_complete | |
---|---|---|---|
0 | 2017-01-01 | python | 6 |
1 | 2017-01-02 | python | 5 |
# Set new indexdf.set_index(pd.DatetimeIndex(df['date']), inplace=True)df
日期 | 语言 | ex_complete | |
---|---|---|---|
日期 | |||
2017-01-01 | 2017-01-01 | python | 6 |
2017-01-02 | 2017-01-02 | python | 5 |
2017-01-03 | 2017-01-03 | python | 10 |
# Check out new indexdf.index
DatetimeIndex(['2017-01-01', '2017-01-02', '2017-01-03'], dtype='datetime64[ns]', name='date', freq=None)
现在, 你可以使用创建的DateTimeIndex分割行:
# Slice and dice data w/ new indexdf.loc['2017-01-02']
date2017-01-02languagepythonex_complete5Name: 2017-01-02 00:00:00, dtype: object
还请注意, .columns属性返回包含df列名称的索引:
# Check out columnsdf.columns
Index(['date', 'language', 'ex_complete'], dtype='object')
这可能会造成一些混乱, 因为这表示df.columns是Index类型。这并不意味着这些列是DataFrame的索引。 df的索引始终由df.index给出。查看我们的pandas DataFrames教程以获取更多有关索引的信息。现在是时候满足层次结构索引了。
熊猫DataFrame的多索引
如果像srcmini一样, 我们的数据集有多种语言怎么办?看一看:
# Import and check out datadf = pd.read_csv('data/user_ex.csv')df
日期 | 语言 | ex_complete | |
---|---|---|---|
0 | 2017-01-01 | python | 6 |
1 | 2017-01-02 | python | 5 |
2 | 2017-01-03 | python | 10 |
3 | 2017-01-01 | [R | 8 |
4 | 2017-01-02 | [R | 8 |
5 | 2017-01-03 | [R | 8 |
# Set indexdf.set_index(['date', 'language'], inplace=True)df
ex_complete | ||
---|---|---|
日期 | 语言 | |
2017-01-01 | python | 6 |
2017-01-02 | python | 5 |
2017-01-03 | python | 10 |
2017-01-01 | [R | 8 |
2017-01-02 | [R | 8 |
2017-01-03 | [R | 8 |
# Check out multi-indexdf.index
MultiIndex(levels=[['2017-01-01', '2017-01-02', '2017-01-03'], ['python', 'r']], labels=[[0, 1, 2, 0, 1, 2], [0, 0, 0, 1, 1, 1]], names=['date', 'language'])
上面告诉你, DataFrame df现在具有一个MultiIndex, 它具有两个级别, 第一个级别由日期给出, 第二个级别由语言给出。回想一下, 上面你可以使用索引和.loc访问器来切片DataFrame:df.loc [‘ 2017-01-02’ ]。为了能够使用多索引切片, 你需要首先对索引进行排序:
# Sort indexdf.sort_index(inplace=True)df
ex_complete | ||
---|---|---|
日期 | 语言 | |
2017-01-01 | python | 6 |
[R | 8 | |
2017-01-02 | python | 5 |
[R | 8 | |
2017-01-03 | python | 10 |
[R | 8 |
# Slice &
dice your DataFramedf.loc[('2017-01-02', 'r')]
ex_complete8Name: (2017-01-02, r), dtype: int64
你现在对分层索引(或多索引)有所了解。现在该看看在使用groupby对象时它们如何产生。
层次结构索引, groupby对象和Split-Apply-Combine 在上一篇文章中, 我们探讨了使用netflix数据进行分组的对象以及split-apply-combine的数据分析原理。让我们快速浏览一下另一个数据集, 这些数据集内置在seaborn软件包中。 “ 提示” 包含小费, total_bill, 星期几和一天中的时间等功能。首先加载并浏览数据:
# Import and check out dataimport seaborn as snstips = sns.load_dataset("tips")tips.head()
total_bill | 小费 | 性别 | 吸烟者 | 天 | 时间 | 尺寸 | |
---|---|---|---|---|---|---|---|
0 | 16.99 | 1.01 | 女 | No | Sun | 晚餐 | 2 |
1 | 10.34 | 1.66 | 男 | No | Sun | 晚餐 | 3 |
2 | 21.01 | 3.50 | 男 | No | Sun | 晚餐 | 3 |
3 | 23.68 | 3.31 | 男 | No | Sun | 晚餐 | 2 |
4 | 24.59 | 3.61 | 女 | No | Sun | 晚餐 | 4 |
# Check out indextips.index
RangeIndex(start=0, stop=244, step=1)
在深入研究计算之前, 总是可以做一些可视化的EDA, 而Seaborn的pairplot函数可以让你大致了解所有数值变量:
# Import pyplot, figures inline, set style, plot pairplotimport matplotlib.pyplot as plt%matplotlib inlinesns.set()sns.pairplot(tips, hue='day');
文章图片
如果要查看” 吸烟者” 和” 不吸烟者” 之间的平均小费之间的差异, 可以将原始数据框架按” 吸烟者” 划分(使用groupby), 应用功能” 均值” 并合并为一个新的DataFrame :
# Get mean of smoker/non-smoker groupsdf = tips.groupby('smoker').mean()df
total_bill | 小费 | 尺寸 | |
---|---|---|---|
吸烟者 | |||
是 | 20.756344 | 3.008710 | 2.408602 |
No | 19.188278 | 2.991854 | 2.668874 |
# Check out new indexdf.index
CategoricalIndex(['Yes', 'No'], categories=['Yes', 'No'], ordered=False, name='smoker', dtype='category')
如果需要, 你可以重置索引, 以使” 吸烟者” 成为DataFrame的一列:
# Reset the indexdf.reset_index()
吸烟者 | total_bill | 小费 | 尺寸 | |
---|---|---|---|---|
0 | 是 | 20.756344 | 3.008710 | 2.408602 |
1 | No | 19.188278 | 2.991854 | 2.668874 |
多个分组和层次结构索引
上面, 你根据” 吸烟者” 功能对提示数据集进行了分组。有时, 你需要根据两个功能对数据集进行分组。例如, 将小费数据集归类为吸烟者/不吸烟者和晚餐/午餐是很自然的。为此, 将希望分组的列名作为列表传递:
# Group by two columnsdf = tips.groupby(['smoker', 'time']).mean()df
total_bill | 小费 | 尺寸 | ||
---|---|---|---|---|
吸烟者 | 时间 | |||
是 | 午餐 | 17.399130 | 2.834348 | 2.217391 |
晚餐 | 21.859429 | 3.066000 | 2.471429 | |
No | 午餐 | 17.050889 | 2.673778 | 2.511111 |
晚餐 | 20.095660 | 3.126887 | 2.735849 |
# Check out indexdf.index
MultiIndex(levels=[['Yes', 'No'], ['Lunch', 'Dinner']], labels=[[0, 0, 1, 1], [0, 1, 0, 1]], names=['smoker', 'time'])
是的。你现在可以做很多有用的事情, 例如获取每个分组中的计数:
# Group by two featurestips.groupby(['smoker', 'time']).size()
smokertimeYesLunch23Dinner70NoLunch45Dinner106dtype: int64
你还可以交换层次结构索引的级别, 以便在索引中的” 吸烟者” 之前出现” 时间” :
# Swap levels of multi-indexdf.swaplevel()
total_bill | 小费 | 尺寸 | ||
---|---|---|---|---|
时间 | 吸烟者 | |||
午餐 | 是 | 17.399130 | 2.834348 | 2.217391 |
晚餐 | 是 | 21.859429 | 3.066000 | 2.471429 |
午餐 | No | 17.050889 | 2.673778 | 2.511111 |
晚餐 | No | 20.095660 | 3.126887 | 2.735849 |
# Unstack your multi-indexdf.unstack()
total_bill | 小费 | 尺寸 | ||||
---|---|---|---|---|---|---|
时间 | 午餐 | 晚餐 | 午餐 | 晚餐 | 午餐 | 晚餐 |
吸烟者 | ||||||
是 | 17.399130 | 21.859429 | 2.834348 | 3.066000 | 2.217391 | 2.471429 |
No | 17.050889 | 20.095660 | 2.673778 | 3.126887 | 2.511111 | 2.735849 |
# Unsstack the outer indexdf.unstack(level=0)
total_bill | 小费 | 尺寸 | ||||
---|---|---|---|---|---|---|
吸烟者 | 是 | No | 是 | No | 是 | No |
时间 | ||||||
午餐 | 17.399130 | 17.050889 | 2.834348 | 2.673778 | 2.217391 | 2.511111 |
晚餐 | 21.859429 | 20.095660 | 3.066000 | 3.126887 | 2.471429 | 2.735849 |
# Check out indexdf.unstack().index
CategoricalIndex(['Yes', 'No'], categories=['Yes', 'No'], ordered=False, name='smoker', dtype='category')
结果, 你现在可以针对这些分组执行所有类型的数据分析。我鼓励你这样做。
日常使用的分层索引 在这篇文章中, 向你介绍了层次结构索引(或多索引), 并看到了它们是如何希望DataFrame索引唯一且有意义地标记DataFrame的行的自然结果。你还了解了当你需要将数据按多列进行分组时, 它们是如何产生的, 并采用了split-apply-combine的原理。我希望你对工作中的层次结构索引感到乐趣。
该帖子来自Jupyter Notebook;你可以在此存储库中找到它。如果你有任何想法, 回应和/或反省, 请随时通过twitter @ hugobowne与我联系。
推荐阅读
- 编写惯用的pandas代码的5个技巧
- 使用Matplotlib查看3D体积数据
- 使用矩阵分解查找相似的名称
- Python循环语句用法教程
- LDA2vec(主题模型中的单词嵌入)
- 学习数据科学-Python和R资源
- 学习数据科学-信息图
- Kaggle教程(EDA和机器学习)
- Google Cloud和数据科学(入门指南)