教你学会 Pandas 不是个人目的,教你轻松玩转 Pandas 才是个人目的。我会经过一系列实例来带入 Pandas 的知识点,让你在学习 Pandas 的路上再也不枯燥。html
声明:我所写的轻松玩转 Pandas 教程都是免费的,若是对你有帮助,你能够持续关注我。python
在 Pandas数据结构详解 | 轻松玩转Pandas(1) 介绍了 Pandas 中经常使用的两种数据结构 Series 以及 DataFrame,这里来看下这些数据结构都有哪些经常使用的功能。数据结构
# 导入相关库
import numpy as np
import pandas as pd
复制代码
当咱们构建好了 Series 和 DataFrame 以后,咱们会常用哪些功能呢?来跟我看看吧。引用上一章节中的场景,咱们有一些用户的的信息,并将它们存储到了 DataFrame 中。app
由于大多数状况下 DataFrame 比 Series 更为经常使用,因此这里以 DataFrame 举例说明,但实际上不少经常使用功能对于 Series 也适用。函数
index = pd.Index(data=["Tom", "Bob", "Mary", "James"], name="name")
data = {
"age": [18, 30, 25, 40],
"city": ["BeiJing", "ShangHai", "GuangZhou", "ShenZhen"],
"sex": ["male", "male", "female", "male"]
}
user_info = pd.DataFrame(data=data, index=index)
user_info
复制代码
age | city | sex | |
---|---|---|---|
name | |||
Tom | 18 | BeiJing | male |
Bob | 30 | ShangHai | male |
Mary | 25 | GuangZhou | female |
James | 40 | ShenZhen | male |
通常拿到数据,咱们第一步须要作的是了解下数据的总体状况,可使用 info
方法来查看。学习
user_info.info()
复制代码
Index: 4 entries, Tom to James
Data columns (total 3 columns):
age 4 non-null int64
city 4 non-null object
sex 4 non-null object
dtypes: int64(1), object(2)
memory usage: 128.0+ bytes
复制代码
若是咱们的数据量很是大,我想看看数据长啥样,我固然不但愿查看全部的数据了,这时候咱们能够采用只看头部的 n 条或者尾部的 n 条。查看头部的 n 条数据可使用 head
方法,查看尾部的 n 条数据可使用 tail
方法。人工智能
user_info.head(2)
复制代码
age | city | sex | |
---|---|---|---|
name | |||
Tom | 18 | BeiJing | male |
Bob | 30 | ShangHai | male |
此外,Pandas 中的数据结构都有 ndarray 中的经常使用方法和属性,如经过 .shape
获取数据的形状,经过 .T
获取数据的转置。spa
user_info.shape
复制代码
(4, 3)
复制代码
user_info.T
复制代码
name | Tom | Bob | Mary | James |
---|---|---|---|---|
age | 18 | 30 | 25 | 40 |
city | BeiJing | ShangHai | GuangZhou | ShenZhen |
sex | male | male | female | male |
若是咱们想要经过 DataFrame 来获取它包含的原有数据,能够经过 .values
来获取,获取后的数据类型实际上是一个 ndarray。设计
user_info.values
复制代码
array([[18, 'BeiJing', 'male'],
[30, 'ShangHai', 'male'],
[25, 'GuangZhou', 'female'],
[40, 'ShenZhen', 'male']], dtype=object)
复制代码
有时候咱们获取到数据以后,想要查看下数据的简单统计指标(最大值、最小值、平均值、中位数等),好比想要查看年龄的最大值,如何实现呢?code
直接对 age
这一列调用 max
方法便可。
user_info.age.max()
复制代码
40
复制代码
相似的,经过调用 min
、mean
、quantile
、sum
方法能够实现最小值、平均值、中位数以及求和。能够看到,对一个 Series
调用 这几个方法以后,返回的都只是一个聚合结果。
来介绍个有意思的方法:cumsum
,看名字就发现它和 sum
方法有关系,事实上确实如此,cumsum
也是用来求和的,不过它是用来累加求和的,也就是说它获得的结果与原始的 Series
或 DataFrame
大小相同。
user_info.age.cumsum()
复制代码
name
Tom 18
Bob 48
Mary 73
James 113
Name: age, dtype: int64
复制代码
能够看到,cummax
最后的结果就是将上一次求和的结果与原始当前值求和做为当前值。这话听起来有点绕。举个例子,上面的 73 = 48 + 25
。cumsum
也能够用来操做字符串类型的对象。
user_info.sex.cumsum()
复制代码
name
Tom male
Bob malemale
Mary malemalefemale
James malemalefemalemale
Name: sex, dtype: object
复制代码
若是想要获取更多的统计方法,能够参见官方连接:Descriptive statistics
虽说常见的各类统计值都有对应的方法,若是我想要获得多个指标的话,就须要调用屡次方法,是否是显得有点麻烦呢?
Pandas 设计者天然也考虑到了这个问题,想要一次性获取多个统计指标,只需调用 describe
方法便可。
user_info.describe()
复制代码
age | |
---|---|
count | 4.000000 |
mean | 28.250000 |
std | 9.251126 |
min | 18.000000 |
25% | 23.250000 |
50% | 27.500000 |
75% | 32.500000 |
max | 40.000000 |
能够看到,直接调用 describe
方法后,会显示出数字类型的列的一些统计指标,如 总数、平均数、标准差、最小值、最大值、25%/50%/75% 分位数。若是想要查看非数字类型的列的统计指标,能够设置 include=["object"] 来得到。
user_info.describe(include=["object"])
复制代码
city | sex | |
---|---|---|
count | 4 | 4 |
unique | 4 | 2 |
top | BeiJing | male |
freq | 1 | 3 |
上面的结果展现了非数字类型的列的一些统计指标:总数,去重后的个数、最多见的值、最多见的值的频数。
此外,若是我想要统计下某列中每一个值出现的次数,如何快速实现呢?调用 value_counts
方法快速获取 Series
中每一个值出现的次数。
user_info.sex.value_counts()
复制代码
male 3
female 1
Name: sex, dtype: int64
复制代码
若是想要获取某列最大值或最小值对应的索引,可使用 idxmax
或 idxmin
方法完成。
user_info.age.idxmax()
复制代码
'James'
复制代码
有时候,咱们会碰到这样的需求,想要将年龄进行离散化(分桶),直白来讲就是将年龄分红几个区间,这里咱们想要将年龄分红 3 个区间段。就可使用 Pandas 的 cut
方法来完成。
pd.cut(user_info.age, 3)
复制代码
name
Tom (17.978, 25.333]
Bob (25.333, 32.667]
Mary (17.978, 25.333]
James (32.667, 40.0]
Name: age, dtype: category
Categories (3, interval[float64]): [(17.978, 25.333] < (25.333, 32.667] < (32.667, 40.0]]
复制代码
能够看到, cut
自动生成了等距的离散区间,若是本身想定义也是没问题的。
pd.cut(user_info.age, [1, 18, 30, 50])
复制代码
name
Tom (1, 18]
Bob (18, 30]
Mary (18, 30]
James (30, 50]
Name: age, dtype: category
Categories (3, interval[int64]): [(1, 18] < (18, 30] < (30, 50]]
复制代码
有时候离散化以后,想要给每一个区间起个名字,能够指定 labels 参数。
pd.cut(user_info.age, [1, 18, 30, 50], labels=["childhood", "youth", "middle"])
复制代码
name
Tom childhood
Bob youth
Mary youth
James middle
Name: age, dtype: category
Categories (3, object): [childhood < youth < middle]
复制代码
除了可使用 cut
进行离散化以外,qcut
也能够实现离散化。cut
是根据每一个值的大小来进行离散化的,qcut
是根据每一个值出现的次数来进行离散化的。
pd.qcut(user_info.age, 3)
复制代码
name
Tom (17.999, 25.0]
Bob (25.0, 30.0]
Mary (17.999, 25.0]
James (30.0, 40.0]
Name: age, dtype: category
Categories (3, interval[float64]): [(17.999, 25.0] < (25.0, 30.0] < (30.0, 40.0]]
复制代码
在进行数据分析时,少不了进行数据排序。Pandas 支持两种排序方式:按轴(索引或列)排序和按实际值排序。
先来看下按索引排序:sort_index
方法默认是按照索引进行正序排的。
user_info.sort_index()
复制代码
age | city | sex | |
---|---|---|---|
name | |||
Bob | 30 | ShangHai | male |
James | 40 | ShenZhen | male |
Mary | 25 | GuangZhou | female |
Tom | 18 | BeiJing | male |
若是想要按照列进行倒序排,能够设置参数 axis=1
和 ascending=False
。
user_info.sort_index(axis=1, ascending=False)
复制代码
sex | city | age | |
---|---|---|---|
name | |||
Tom | male | BeiJing | 18 |
Bob | male | ShangHai | 30 |
Mary | female | GuangZhou | 25 |
James | male | ShenZhen | 40 |
若是想要实现按照实际值来排序,例如想要按照年龄排序,如何实现呢?
使用 sort_values
方法,设置参数 by="age"
便可。
user_info.sort_values(by="age")
复制代码
age | city | sex | |
---|---|---|---|
name | |||
Tom | 18 | BeiJing | male |
Mary | 25 | GuangZhou | female |
Bob | 30 | ShangHai | male |
James | 40 | ShenZhen | male |
有时候咱们可能须要按照多个值来排序,例如:按照年龄和城市来一块儿排序,能够设置参数 by 为一个 list 便可。
注意:list 中每一个元素的顺序会影响排序优先级的。
user_info.sort_values(by=["age", "city"])
复制代码
age | city | sex | |
---|---|---|---|
name | |||
Tom | 18 | BeiJing | male |
Mary | 25 | GuangZhou | female |
Bob | 30 | ShangHai | male |
James | 40 | ShenZhen | male |
通常在排序后,咱们可能须要获取最大的n个值或最小值的n个值,咱们可使用 nlargest
和 nsmallest
方法来完成,这比先进行排序,再使用 head(n)
方法快得多。
user_info.age.nlargest(2)
复制代码
name
James 40
Bob 30
Name: age, dtype: int64
复制代码
虽然说 Pandas 为咱们提供了很是丰富的函数,有时候咱们可能须要本身定制一些函数,并将它应用到 DataFrame 或 Series。经常使用到的函数有:map
、apply
、applymap
。
map
是 Series 中特有的方法,经过它能够对 Series 中的每一个元素实现转换。
若是我想经过年龄判断用户是否属于中年人(30岁以上为中年),经过 map
能够轻松搞定它。
# 接收一个 lambda 函数
user_info.age.map(lambda x: "yes" if x >= 30 else "no")
复制代码
name
Tom no
Bob yes
Mary no
James yes
Name: age, dtype: object
复制代码
又好比,我想要经过城市来判断是南方仍是北方,我能够这样操做。
city_map = {
"BeiJing": "north",
"ShangHai": "south",
"GuangZhou": "south",
"ShenZhen": "south"
}
# 传入一个 map
user_info.city.map(city_map)
复制代码
name
Tom north
Bob south
Mary south
James south
Name: city, dtype: object
复制代码
apply
方法既支持 Series,也支持 DataFrame,在对 Series 操做时会做用到每一个值上,在对 DataFrame 操做时会做用到全部行或全部列(经过 axis
参数控制)。
# 对 Series 来讲,apply 方法 与 map 方法区别不大。
user_info.age.apply(lambda x: "yes" if x >= 30 else "no")
复制代码
name
Tom no
Bob yes
Mary no
James yes
Name: age, dtype: object
复制代码
# 对 DataFrame 来讲,apply 方法的做用对象是一行或一列数据(一个Series)
user_info.apply(lambda x: x.max(), axis=0)
复制代码
age 40
city ShenZhen
sex male
dtype: object
复制代码
applymap
方法针对于 DataFrame,它做用于 DataFrame 中的每一个元素,它对 DataFrame 的效果相似于 apply
对 Series 的效果。
user_info.applymap(lambda x: str(x).lower())
复制代码
age | city | sex | |
---|---|---|---|
name | |||
Tom | 18 | beijing | male |
Bob | 30 | shanghai | male |
Mary | 25 | guangzhou | female |
James | 40 | shenzhen | male |
在使用 DataFrame 的过程当中,常常会遇到修改列名,索引名等状况。使用 rename
轻松能够实现。
修改列名只须要设置参数 columns
便可。
user_info.rename(columns={"age": "Age", "city": "City", "sex": "Sex"})
复制代码
Age | City | Sex | |
---|---|---|---|
name | |||
Tom | 18 | BeiJing | male |
Bob | 30 | ShangHai | male |
Mary | 25 | GuangZhou | female |
James | 40 | ShenZhen | male |
相似的,修改索引名只须要设置参数 index
便可。
user_info.rename(index={"Tom": "tom", "Bob": "bob"})
复制代码
age | city | sex | |
---|---|---|---|
name | |||
tom | 18 | BeiJing | male |
bob | 30 | ShangHai | male |
Mary | 25 | GuangZhou | female |
James | 40 | ShenZhen | male |
若是想要获取每种类型的列数的话,可使用 get_dtype_counts
方法。
user_info.get_dtype_counts()
复制代码
int64 1
object 2
dtype: int64
复制代码
若是想要转换数据类型的话,能够经过 astype
来完成。
user_info["age"].astype(float)
复制代码
name
Tom 18.0
Bob 30.0
Mary 25.0
James 40.0
Name: age, dtype: float64
复制代码
有时候会涉及到将 object 类型转为其余类型,常见的有转为数字、日期、时间差,Pandas 中分别对应 to_numeric
、to_datetime
、to_timedelta
方法。
这里给这些用户都添加一些关于身高的信息。
user_info["height"] = ["178", "168", "178", "180cm"]
user_info
复制代码
age | city | sex | height | |
---|---|---|---|---|
name | ||||
Tom | 18 | BeiJing | male | 178 |
Bob | 30 | ShangHai | male | 168 |
Mary | 25 | GuangZhou | female | 178 |
James | 40 | ShenZhen | male | 180cm |
如今将身高这一列转为数字,很明显,180cm 并不是数字,为了强制转换,咱们能够传入 errors
参数,这个参数的做用是当强转失败时的处理方式。
默认状况下,errors='raise'
,这意味着强转失败后直接抛出异常,设置 errors='coerce'
能够在强转失败时将有问题的元素赋值为 pd.NaT(对于datetime和timedelta)或 np.nan(数字)。设置 errors='ignore'
能够在强转失败时返回原有的数据。
pd.to_numeric(user_info.height, errors="coerce")
复制代码
name
Tom 178.0
Bob 168.0
Mary 178.0
James NaN
Name: height, dtype: float64
复制代码
pd.to_numeric(user_info.height, errors="ignore")
复制代码
name
Tom 178
Bob 168
Mary 178
James 180cm
Name: height, dtype: object
复制代码
想要学习更多关于人工智能的知识,请关注公众号:AI派
这里我将整篇文章的内容整理成了pdf,想要pdf文件的能够在公众号后台回复关键字:pandas02。
更多Pandas知识见:轻松玩转Pandas