src: https://mp.weixin.qq.com/s/j71IPWmT57g3VTajGhgN7Q author: 俊欣 公众号: 关于数据分析与可视化
本篇我们继续前面pandas系列教程的探讨,今天小编会介绍pandas库当中一些非常基础的方法与函数,希望大家看了之后会有所收获。
准备需要的数据集
我们先准备生成一些随机数,作为后面需要用到的数据集
import pandas as pd
import numpy as np
index = pd.date_range("1/1/2000", periods=8)
series = pd.Series(np.random.randn(5), index=["a", "b", "c", "d", "e"])
df = pd.DataFrame(np.random.randn(8, 3),
index=index,
columns=["A", "B", "C"])
Head and tail
head()和tail()方法是用来查看数据集当中的前几行和末尾几行的,默认是查看5行,当然读者朋友也可以自行设定行数
series2 = pd.Series(np.random.randn(100))
series2.head()
0 0.578276
1 0.643313
2 -0.336030
3 -0.422468
4 -0.493812
dtype: float64
# 同理
series2.tail()
95 1.307962
96 1.165135
97 0.717692
98 0.605668
99 0.264990
dtype: float64
数据的统计分析
在pandas当中用describe()方法来对表格中的数据做一个概括性的统计分析,例如
series2.describe()
count 100.000000
mean 0.106277
std 1.027541
min -2.554005
25% -0.510912
50% 0.028765
75% 0.795444
max 2.512260
dtype: float64
当然,我们也可以设置好输出的分位
series2.describe(percentiles=[0.05, 0.25, 0.75, 0.95])
count 100.000000
mean 0.106277
std 1.027541
min -2.554005
5% -1.450067
25% -0.510912
50% 0.028765
75% 0.795444
95% 1.757926
max 2.512260
dtype: float64
对于离散型的数据来说,describe()方法给出的结果则会简洁很多
s = pd.Series(["a", "a", "b", "b", "a", "a", "d", "c", "d", "a"])
s.describe()
count 10
unique 4
top a
freq 5
dtype: object
要是表格中既包含了离散型数据,也包含了连续型的数据,默认的话,describe()是会针对连续型数据进行统计分析
df2 = pd.DataFrame({"a": ["Yes", "Yes", "No", "No"], "b": np.random.randn(4)})
df2.describe()
| | b |
|:------|---------:|
| count | 4 |
| mean | 0.967026 |
| std | 0.859657 |
| min | 0.204027 |
| 25% | 0.233797 |
| 50% | 0.947075 |
| 75% | 1.6803 |
| max | 1.76993 |
当然我们也可以指定让其强制统计分析离散型数据或者连续型数据
df2.describe(include=["object"])
| | a |
|:-------|:----|
| count | 4 |
| unique | 2 |
| top | Yes |
| freq | 2 |
同理,我们也可以指定连续型的数据进行统计分析
df2.describe(include=["number"])
| | b |
|:------|---------:|
| count | 4 |
| mean | 0.967026 |
| std | 0.859657 |
| min | 0.204027 |
| 25% | 0.233797 |
| 50% | 0.947075 |
| 75% | 1.6803 |
| max | 1.76993 |
如果我们都要去做统计分析,可以这么来执行
df2.describe(include="all")
| | a | b |
|:-------|:----|-----------:|
| count | 4 | 4 |
| unique | 2 | nan |
| top | Yes | nan |
| freq | 2 | nan |
| mean | nan | 0.967026 |
| std | nan | 0.859657 |
| min | nan | 0.204027 |
| 25% | nan | 0.233797 |
| 50% | nan | 0.947075 |
| 75% | nan | 1.6803 |
| max | nan | 1.76993 |
最大/最小值的位置
idxmin()和idxmax()方法是用来查找表格当中最大/最小值的位置,返回的是值的索引
s1 = pd.Series(np.random.randn(5))
s1
0 2.244266
1 1.398258
2 -1.827026
3 -0.058691
4 0.275471
dtype: float64
s1.idxmin(), s1.idxmax()
(2, 0)
用在DataFrame上面的话,如下
df1 = pd.DataFrame(np.random.randn(5, 3),
columns=["A", "B", "C"])
df1.idxmin(axis=0)
| | 0 |
|:---|----:|
| A | 2 |
| B | 3 |
| C | 2 |
同理,我们将axis参数改成1
df1.idxmin(axis=1)
| | 0 |
|---:|:----|
| 0 | B |
| 1 | B |
| 2 | A |
| 3 | B |
| 4 | B |
value_counts()方法
pandas当中的value_counts()方法主要用于数据表的计数以及排序,用来查看表格当中,指定列有多少个不同的数据值并且计算不同值在该列当中出现的次数,先来看一个简单的例子
df = pd.DataFrame({'城市': ['北京', '广州', '上海', '上海', '杭州', '成都', '香港', '南京', '北京', '北京'],
'收入': [10000, 10000, 5500, 5500, 4000, 50000, 8000, 5000, 5200, 5600],
'年龄': [50, 43, 34, 40, 25, 25, 45, 32, 25, 25]})
df["城市"].value_counts()
北京 3
上海 2
广州 1
杭州 1
南京 1
香港 1
成都 1
Name: 城市, dtype: int64
可以看到北京出现了3次,上海出现了2次,并且默认采用的是降序来排列的,下面我们来看一下用升序的方式来排列一下收入这一列
df["收入"].value_counts(ascending=True)
5600 1
5000 1
8000 1
5200 1
50000 1
4000 1
10000 2
5500 2
Name: 收入, dtype: int64
同时里面也还可以利用参数normalize=True,来计算不同值的计数占比
df['年龄'].value_counts(ascending=True,
normalize=True)
32 0.1
34 0.1
50 0.1
40 0.1
43 0.1
45 0.1
25 0.4
Name: 年龄, dtype: float64
数据分组
我们可以使用cut()方法以及qcut()方法来对表格中的连续型数据分组,首先我们看一下cut()方法,假设下面这组数据代表的是小组每个成员的年龄
ages = np.array([2,3,10,40,36,45,58,62,85,89,95,18,20,25,35,32])
pd.cut(ages, 5)
[(1.907, 20.6], (1.907, 20.6], (1.907, 20.6], (39.2, 57.8], (20.6, 39.2], ..., (1.907, 20.6], (1.907, 20.6], (20.6, 39.2], (20.6, 39.2], (20.6, 39.2]]
Length: 16
Categories (5, interval[float64]): [(1.907, 20.6] < (20.6, 39.2] < (39.2, 57.8] < (57.8, 76.4] < (76.4, 95.0]]
由上可以看到用cut()方法将数据平分成了5个区间,且区间两边都有扩展以包含最大值和最小值,当然我们也可以给每一个区间加上标记
pd.cut(ages, 5, labels=[u"婴儿",u"少年",u"青年",u"中年",u"老年"])
['婴儿', '婴儿', '婴儿', '青年', '少年', ..., '婴儿', '婴儿', '少年', '少年', '少年']
Length: 16
Categories (5, object): ['婴儿' < '少年' < '青年' < '中年' < '老年']
而对于qcut()方法来说,我们可以指定区间来进行分组,例如
pd.qcut(ages, [0,0.5,1], labels=['小朋友','大孩子'])
['小朋友', '小朋友', '小朋友', '大孩子', '大孩子', ..., '小朋友', '小朋友', '小朋友', '小朋友', '小朋友']
Length: 16
Categories (2, object): ['小朋友' < '大孩子']
这里将年龄这组数据分成两部分[0, 0.5, 1],一组是标上标记小朋友,另一组是大孩子,不过通常情况下,我们用的cut()方法比较多
引用函数
要是在表格当中引用其他的方法,或者是自建的函数,可以使用通过pandas当中的以下这几个方法
- pipe()
- apply()和applymap()
- agg()和transform()
pipe()方法
首先我们来看pipe()这个方法,我们可以将自己定义好的函数,以链路的形式一个接着一个传给我们要处理的数据集上
def extract_city_name(df):
df["state_name"] = df["state_and_code"].str.split(",").str.get(0)
return df
def add_country_name(df, country_name=None):
df["state_and_country"] = df["state_name"] + country_name
return df
然后我们用pip()这个方法来将上面我们定义的函数串联起来
df_p = pd.DataFrame({"city_and_code": ["Arizona, AZ"]})
df_p = pd.DataFrame({"state_and_code": ["Arizona, AZ"]})
df_p.pipe(extract_city_name).pipe(add_country_name, country_name="_USA")
| | state_and_code | state_name | state_and_country |
|---:|:-----------------|:-------------|:--------------------|
| 0 | Arizona, AZ | Arizona | Arizona_USA |
apply()方法和applymap()方法
apply()方法可以对表格中的数据按照行或者是列方向进行处理,默认是按照列方向,如下
df.apply(np.mean)
A -0.101751
B -0.360288
C -0.637433
dtype: float64
当然,我们也可以通过axis参数来进行调节
df.apply(np.mean, axis = 1)
0 -0.803675
1 -0.179640
2 -1.200973
3 0.156888
4 0.381631
5 0.049274
6 1.174923
7 0.612591
dtype: float64
除此之外,我们也可以直接调用匿名函数lambda的形式
df.apply(lambda x: x.max() - x.min())
A 1.922863
B 2.874672
C 1.943930
dtype: float64
也可以调用自己定义的函数方法
df = pd.DataFrame(np.random.randn(5, 3), columns=["A", "B", "C"])
def normalize(x):
return (x - x.mean()) / x.std()
我们用上apply()方法
df.apply(normalize)
A B C
0 1.149795 0.390263 -0.813770
1 0.805843 -0.532374 0.859627
2 0.047824 -0.085334 -0.067179
3 -0.903319 -1.215023 1.149538
4 -1.100144 1.442467 -1.128216
apply()方法作用于数据集当中的每个行或者是列,而applymap()方法则是对数据集当中的所有元素都进行处理
df = pd.DataFrame({'key1' : ['a', 'c', 'b', 'b', 'd'],
'key2' : ['one', 'two', 'three', 'two', 'one'],
'data1' : np.arange(1, 6),
'data2' : np.arange(10,15)})
df
key1 key2 data1 data2
0 a one 1 10
1 c two 2 11
2 b three 3 12
3 b four 4 13
4 d five 5 14
我们来自定义一个函数
def add_A(x):
return "A" + str(x)
df.applymap(add_A)
key1 key2 data1 data2
0 Aa Aone A1 A10
1 Ac Atwo A2 A11
2 Ab Athree A3 A12
3 Ab Afour A4 A13
4 Ad Afive A5 A14
我们然后也可以通过lambda()自定义函数方法,然后来去除掉这个A
df.applymap(add_A).applymap(lambda x: x.split("A")[1])
key1 key2 data1 data2
0 a one 1 10
1 c two 2 11
2 b three 3 12
3 b four 4 13
4 d five 5 14
agg()方法和transform()方法
agg()方法本意上是聚合函数,我们可以将用于统计分析的一系列方法都放置其中,并且放置多个
df = pd.DataFrame(np.random.randn(5, 3),
columns=["A", "B", "C"])
df.agg(np.sum)
A 2.042573
B 2.189269
C -1.066976
dtype: float64
当然,当中的np.sum部分也可以用字符串来表示,例如
df.agg("sum")
A 2.042573
B 2.189269
C -1.066976
dtype: float64
我们尝试在当中放置多个统计分析的函数方法
df.agg(["sum", "mean", "median"])
当然我们也可以和lambda匿名函数混合着搭配
df.agg(["sum", lambda x: x.mean()])
A B C
sum -0.066486 -1.288341 -1.236244
<lambda> -0.013297 -0.257668 -0.247249
或者和自己定义的函数方法混合着用
def my_mean(x):
return x.mean()
df.agg(["sum", my_mean])
A B C
sum -4.850201 -1.544773 0.429007
my_mean -0.970040 -0.308955 0.085801
与此同时,我们在agg()方法中添加字典,实现不同的列使用不同的函数方法
df.agg({"A": "sum", "B": "mean"})
A -0.801753
B 0.097550
dtype: float64
索引和列名的重命名
针对索引和列名的重命名,我们可以通过pandas当中的rename()方法来实现,例如我们有这样一个数据集
df1 = pd.DataFrame(np.random.randn(5, 3),
columns=["A", "B", "C"],
index = ["a", "b", "c", "d", "e"])
df1
A B C
a 0.343690 0.869984 -1.929814
b 1.025613 0.470155 -0.242463
c -0.400908 -0.362684 0.226857
d -1.339706 -0.302005 -1.784452
e -0.957026 -0.813600 0.215098
我们可以这样来操作
df1.rename(columns={"A": "one", "B": "two", "C": "three"},
index={"a": "apple", "b": "banana", "c": "cat"})
one two three
apple 0.383813 0.588964 -0.162386
banana -0.462068 -2.938896 0.935492
cat -0.059807 -1.987281 0.095432
d -0.085230 2.013733 -1.324039
e -0.678352 0.306776 0.808697
当然我们可以拆开来,单独对行或者是列进行重命名,对列的重命名可以这么来做
df1.rename({"A": "one", "B": "two", "C": "three"},
axis = "columns")
one two three
a -0.997108 -1.383011 0.474298
b 1.009910 0.286303 1.120783
c 1.130700 -0.566922 1.841451
d -0.350438 -0.171079 -0.079804
e 0.988050 -0.524604 0.653306
排序
在pandas当中,我们可以针对数据集当中的值来进行排序
df1 = pd.DataFrame(
{"one": [2, 1, 1, 1],
"two": [1, 3, 2, 4],
"three": [5, 4, 3, 2]}
)
df1
one two three
0 2 1 5
1 1 3 4
2 1 2 3
3 1 4 2
我们按照“three”这一列当中的数值来进行排序
df1.sort_values(by = "three")
one two three
3 1 4 2
2 1 2 3
1 1 3 4
0 2 1 5
我们也可以依照多列进行排序
df1.sort_values(by = ["one", "two"])
one two three
2 1 2 3
1 1 3 4
3 1 4 2
0 2 1 5
在“one”这一列相等的时候,比较“two”这一列数值的大小,在排序的过程当中,默认采用的都是升序,我们可以改成降序来进行编排
df1.sort_values("two", ascending=False)
one two three
3 1 4 2
1 1 3 4
2 1 2 3
0 2 1 5
数据类型的转换
最后涉及到的是数据类型的转换,在这之前,我们先得知道如何来查看数据的类型,pandas当中有相应的方法可以处理
df2 = pd.DataFrame(
{
"A": pd.Series(np.random.randn(5), dtype="float16"),
"B": pd.Series(np.random.randn(5)),
"C": pd.Series(np.array(np.random.randn(5), dtype="uint8")),
}
)
df2
A B C
0 -0.498779 -0.501512 0
1 -0.055817 -0.528227 254
2 -0.914551 0.763298 1
3 -0.916016 1.366833 0
4 1.993164 1.834457 0
我们通过dtypes属性来查看数据的类型
A float16
B float64
C uint8
dtype: object
而通过astype()方法来实现数据类型的转换
df2["B"].astype("int64")
0 0
1 0
2 0
3 2
4 1
Name: B, dtype: int64
根据数据类型来筛选
与此同时,我们也可以根据相对应的数据类型来进行筛选,运用pandas当中的select_dtypes方法,我们先来创建一个数据集包含了各种数据类型的
df = pd.DataFrame(
{
"string_1": list("abcde"),
"int64_1": list(range(1, 6)),
"uint8_1": np.arange(3, 8).astype("u1"),
"float64_1": np.arange(4.0, 9.0),
"bool1": [True, False, True, True, False],
"bool2": [False, True, False, False, True],
"dates_1": pd.date_range("now", periods=5),
"category_1": pd.Series(list("ABCDE")).astype("category"),
}
)
df
string_1 int64_1 uint8_1 ... bool2 dates_1 category_1
0 a 1 3 ... False 2021-11-10 10:43:05.957685 A
1 b 2 4 ... True 2021-11-11 10:43:05.957685 B
2 c 3 5 ... False 2021-11-12 10:43:05.957685 C
3 d 4 6 ... False 2021-11-13 10:43:05.957685 D
4 e 5 7 ... True 2021-11-14 10:43:05.957685 E
我们先来查看一下各个列的数据类型
df.dtypes
string_1 object
int64_1 int64
uint8_1 uint8
float64_1 float64
bool1 bool
bool2 bool
dates_1 datetime64[ns]
category_1 category
dtype: object
我们筛选类型为布尔值的数据
df.select_dtypes(include=[bool])
bool1 bool2
0 True False
1 False True
2 True False
3 True False
4 False True
筛选出数据类型为整型的数据
df.select_dtypes(include=['int64'])
int64_1
0 1
1 2
2 3
3 4
4 5