视频教程

1.pandas的常用数据类型

1.Series 一维,带标签数组

2.DataFrame 二维,Series容器

2.pandas之Series创建

图片2

3.pandas之Series切片和索引

图片3

4.pandas之Series的索引和值

图片4

5.pandas之读取外部数据

我们的这组数据存在csv中,我们直接使用pd. read_csv即可

和我们想象的有些差别,我们以为他会是一个Series类型,但是他是一个DataFrame,那么接下来我们就来了解这种数据类型

==小示例:==

现在假设我们有一个组关于狗的名字的统计数据,那么为了观察这组数据的情况,我们应该怎么做呢?

1
2
3
import pandas as pd
df = pd.read_csv('./dogNames2.csv')
print(df)

==效果展示==

图片5

6.pandas之DataFrame

图片6

DataFrame对象既有行索引,又有列索引

行索引,表明不同行,横向索引,叫index,0轴,axis=0

列索引,表名不同列,纵向索引,叫columns,1轴,axis=1

图片7

图片8

那么回到之前我们读取的狗名字统计的数据上,我们尝试一下刚刚的方法

那么问题来了:

很多同学肯定想知道使用次数最高的前几个名字是什么呢?

df.sort_values(by="Count_AnimalName",ascending=*False*)

==dataframe排序==

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import pandas as pd
df = pd.read_csv('./dogNames2.csv')
# print(df)
# print('*'*100)
# print(df.head())
# print('*'*100)
# print(df.info())
# print('*'*100)
# print(df.describe())

# 以Count_AnimalName来排序(默认升序)
# df = df.sort_values(by='Count_AnimalName')
# ascending=True 为升序,False为倒序
df = df.sort_values(by='Count_AnimalName',ascending=False)
print(df.head(10))

7.pandas之取行或者列

刚刚我们知道了如何给数据按照某一行或者列排序,那么现在我们想单独研究使用次数前100的数据,应该如何做?

df_sorted = df.sort_values(by="Count_AnimalName")

df_sorted[:100]

那么问题来了:

我们具体要选择某一列该怎么选择呢?df[" Count_AnimalName "]

我们要同时选择行和列改怎么办?df[:100][" Count_AnimalName "]

8.pandas之loc

还有更多的经过pandas优化过的选择方式:

1.df.loc 通过标签索引行数据

2.df.iloc 通过位置获取行数据

图片9

图片10

9.pandas之布尔索引

回到之前狗的名字的问题上,假如我们想找到所有的使用次数超过800的狗的名字,应该怎么选择?

图片11

回到之前狗的名字的问题上,假如我们想找到所有的使用次数超过700并且名字的字符串的长度大于4的狗的名字,应该怎么选择?

图片12

10.pandas之字符串方法

图片13

11.缺失数据的处理

观察下面这组数据

图片14

我们的数据缺失通常有两种情况:

一种就是空,None等,在pandas是NaN(和np.nan一样)另一种是我们让其为0,蓝色框中

对于NaN的数据,在numpy中我们是如何处理的?

在pandas中我们处理起来非常容易

判断数据是否为NaN:pd.isnull(df),pd.notnull(df)

处理方式1:删除NaN所在的行列dropna (axis=0, how='any', inplace=False)

处理方式2:填充数据,t.fillna(t.mean()),t.fiallna(t.median()),t.fillna(0)

处理为0的数据:t[t==0]=np.nan

当然并不是每次为0的数据都需要处理

计算平均值等情况,nan是不参与计算的,但是0会

==示例==

假设现在我们有一组从2006年到2016年1000部最流行的电影数据,我们想知道这些电影数据中评分的平均分,导演的人数等信息,我们应该怎么获取?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
import pandas as pd, numpy as np
from matplotlib import pyplot as plt

df = pd.read_csv('IMDB-Movie-Data.csv')
print(type(df))
print(df.info())
print(df.head())
print(df['Rating'].values)
print(df['Rating'].describe())
# df['Rating'].mean()为numpy类型的数据,不能使用字符串拼接,需要先转换为字符串
# 电影评分平均值
print('电影平均分:' + str(df['Rating'].mean()))
# 导演的人数
# df['Director'].tolist() # python tolist()方法:将数组或者矩阵转换成列表
# set(df['Director'].tolist()) # 使用set() 将数组去重并转换为set集合,集合是一个无序的不重复元素序列
print('导演人数:', len(set(df['Director'].tolist())))
# 别一种方法:df['Director'].unique()可以将df['Director']去重,并返回
print('导演人数:', len(df['Director'].unique()))
# 由于每一部电影的演员有多人,所以先使用split(',')以逗号分隔,让每组数据的字符串重组为数组
print('所有演员二维数据:')
print(df['Actors'].str.split(',').tolist())
temp_list = df['Actors'].str.split(',').tolist()
# 将二维数组展开
nums = [i for j in temp_list for i in j]
print('所有演员一维数组:')
print(nums)
# 数组去重,并取总数
actors = len(set(nums)) # 使用set集合的特点去重
actors2 = len(pd.Series(nums).unique()) # 使用pandas的unique方法去重
print('去重后演员的总人数:', actors, actors2)
# 电影时长的最大最小值:
max_runtime = df['Runtime (Minutes)'].max()
max_runtime_index = df['Runtime (Minutes)'].argmax()
min_runtime = df['Runtime (Minutes)'].min()
min_runtime_index = df['Runtime (Minutes)'].argmin()
runtime_median = df['Runtime (Minutes)'].median()

图片15

==示例==

对于这一组电影数据,如果我们希望统计电影分类(genre)的情况,应该如何处理数据?

思路:重新构造一个全为0的数组,列名为分类,如果某一条数据中分类出现过,就让0变为1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
from matplotlib import pyplot as plt
import numpy as np
import pandas as pd

df = pd.read_csv('IMDB-Movie-Data.csv')
print(df['Genre'])
temp_list = df['Genre'].str.split(',').tolist()
print(temp_list)
# 利用set展开二维列表并去重
genre_list = list(set([i for j in temp_list for i in j]))
print(genre_list)
# 构造全为0的DataFrame:df一样的行数,分类总数的列数,索引为分类数据genre_list
# np.zeros((a,b))里面传的是元组
zeros_df = pd.DataFrame(np.zeros((df.shape[0], len(genre_list))), columns=genre_list)
print(zeros_df)
for i in range(df.shape[0]):
zeros_df.loc[i, temp_list[i]] = 1
# 显示所有列
pd.set_option('display.max_columns', None)
# 显示所有列
# pd.set_option('display.max_columns', None)
# #显示所有行
# pd.set_option('display.max_rows', None)
# #设置value的显示长度为100,默认为50
# pd.set_option('max_colwidth',100)
print(zeros_df.head(1))
# 统计每个分类的电影的数量和
genre_count = zeros_df.sum(axis=0)
print(genre_count)
# 排序
genre_count = genre_count.sort_values()
# 画柱状图
_x = genre_count.index
_y = genre_count.values
plt.figure(figsize=(20, 8), dpi=80)
plt.bar(range(len(_x)), _y)
plt.xticks(range(len(_x)), _x)
plt.show()

图片16

12.数据合并之join

join:默认情况下他是把行索引相同的数据合并到一起

图片17

13.数据合并之merge

merge:按照指定的列把数据按照一定的方式合并到一起

图片18

==示例:==

现在我们有一组关于全球星巴克店铺的统计数据,如果我想知道美国的星巴克数量和中国的哪个多,或者我想知道中国每个省份星巴克的数量的情况,那么应该怎么办?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
import numpy as np
import pandas as pd

df = pd.read_csv('starbucks_store_worldwide.csv')
# print(df)
# print(df.info())
# df_country = df.groupby('Country') # 生成一个DataFrameGroupBy object
# print(df_country)
# # 显示所有列
# pd.set_option('display.max_columns', None)
# # 遍历
# # for i in df_country:
# # print(i) # 遍历后的每一个数据都是一个元组
#
# # 由于遍历后的每一个值都是元组,所以还可以这样遍历
# for i, j in df_country:
# print(i, j, type(j)) # i为国家信息,j为一个DataFrame,其中所有的country字段均为i
# print('*' * 100)
#
# # 调用聚合方法
# print(df_country.count()) # count()可以统计每个字段的总数
# print(df_country['City'].count()) # 单独统计一个字段的总数
# #
"""
平均值,中位数等方法也可以使用,但这里使用没有意义,因为都是字符串
count:分组中非NA值的数量
sum:非NA的和
mean:非NA值的平均值
median:非NA值的算术中位数
std、var: 无偏(分母为n-a)标准差和方差
min,max:非NA值的最小值和最大值 """
# country_count = df_country['City'].count()
# # 美国和中国的星巴克店铺数量
# print('美国:', country_count['US'])
# print('中国:', country_count['CN'])

# 统计中国每个省份的星巴克
china_data = df[df['Country'] == 'CN'] # 取出中国的星巴克数据,这里可以不需要分组,直接取数据
# print(china_data)
# print(china_data.info())
# province_data = china_data.groupby('State/Province').count()['Brand']
# print(province_data)
# groupby可以传入多个条件来分组
print(df['Brand'])
china_data_group = df.groupby(
by=[df['Country'], df['State/Province']]).count() # 返回一个Series,列索引有两个,一个是country,一个是State/Province
print(china_data_group)
print(china_data_group['Brand'])

# 以下三种写法,结果相同
group1 = df.groupby(by=[df['Country'], df['State/Province']]).count()['Brand']
group2 = df['Brand'].groupby(by=[df['Country'], df['State/Province']]).count()
group3 = df.groupby(by=[df['Country'], df['State/Province']])['Brand'].count()
print(group1, type(group1))
print('*' * 100)
print(group2, type(group2))
print('*' * 100)
print(group3, type(group3))
# 取值可以为DataFrame,需要使用一个小技巧
group4 = df[['Brand']].groupby(by=[df['Country'], df['State/Province']]).count()
print('*' * 100)
print(group4, type(group4))
print(group1.index)

14.分组和聚合

grouped = df.groupby(by="columns_name")

grouped是一个DataFrameGroupBy对象,是可迭代的

grouped中的每一个元素是一个元组

元组里面是(索引(分组的值),分组之后的DataFrame)

DataFrameGroupBy对象有很多经过优化的方法

图片19

如果我们需要对国家和省份进行分组统计,应该怎么操作呢?

grouped = df.groupby(by=[df["Country"],df["State/Province"]])

很多时候我们只希望对获取分组之后的某一部分数据,或者说我们只希望对某几列数据进行分组,这个时候我们应该怎么办呢?

获取分组之后的某一部分数据:

df.groupby(by=["Country","State/Province"])["Country"].count()

对某几列数据进行分组:

df["Country"].groupby(by=[df["Country"],df["State/Province"]]).count()

观察结果,由于只选择了一列数据,所以结果是一个Series类型

如果我想返回一个DataFrame类型呢?

t1 = df[["Country"]].groupby(by=[df["Country"],df["State/Province"]]).count()
t2 = df.groupby(by=["Country","State/Province"])[["Country"]].count()

以上的两条命令结果一样

和之前的结果的区别在于当前返回的是一个DataFrame类型

简单的索引操作:

•获取index:df.index

•指定index :df.index = ['x','y']

•重新设置index : df.reindex(list("abcedf"))

•指定某一列作为index :df.set_index("Country",drop=False)

•返回index的唯一值:df.set_index("Country").index.unique()

15.Series复合索引

图片20

图片21

图片22

==示例==

现在我们有2015到2017年25万条911的紧急电话的数据,请统计出出这些数据中不同类型的紧急情况的次数,如果我们还想统计出不同月份不同类型紧急电话的次数的变化情况,应该怎么做呢?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
import pandas as pd, numpy as np
from matplotlib import pyplot as plt

df = pd.read_csv('911.csv')
# 显示所有列
pd.set_option('display.max_columns', None)
# print(df.head())
# print(df.info())
# print(df['title'].str.split(':'))
# print(df['title'].str.split(':')[0]) # 不能取到数据
# to_list()将序列转换为数组
temp_list = df['title'].str.split(':').to_list()
# temp_list = df['title'].str.split(':').tolist()
print(temp_list)
# 遍历并取出第一项数据并去重
cate_list = list(set([i[0] for i in temp_list]))
print(cate_list)
# 构造一个DataFrame,三列,与df同行,数据全为0
zeros_df = pd.DataFrame(np.zeros((df.shape[0], len(cate_list))), columns=cate_list)
print(zeros_df)
#  由于df数据量太大,如果直接遍历,会消耗很长时间
# for i in range(df.shape[0]):
# zeros_df.loc[i,temp_list[i][0]] = 1
#
# print(zeros_df)

# 遍历cate_list,只需要循环三次
for cate in cate_list:
# df['title'].str.contains(cate)返回的是一个布尔型数组,行数与zeros_df相同,列数为三列,
# 包含cate的那一列为True,具体可见5.62布尔索引章节
zeros_df[cate][df['title'].str.contains(cate)] = 1

# print(zeros_df)

# 统计邮寄类型的数量
sum_ret = zeros_df.sum(axis=0)
print(sum_ret)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import pandas as pd, numpy as np
from matplotlib import pyplot as plt

df = pd.read_csv('911.csv')
# #显示所有行
pd.set_option('display.max_rows', None)
print(df.head())
print(df.info())

# to_list()将序列转换为数组
temp_list = df['title'].str.split(':').to_list()

# print(temp_list)
# 遍历并取出第一项的分类
cate_list = [i[0] for i in temp_list]
# print(cate_list)
cate_df = pd.DataFrame(np.array(cate_list).reshape((df.shape[0]), 1), columns=['cate'])
print(cate_df)
# 添加一列,列索引为cate
df['cate'] = cate_df
# print(df['cate'])
print(df.groupby(by='cate').count()['title'])

16.pandas中的时间序列

==生成一段时间范围==

pd.date_range(start=None, end=None, periods=None, freq='D')

start和end以及freq配合能够生成start和end范围内以频率freq的一组时间索引

start和periods以及freq配合能够生成从start开始的频率为freq的periods个时间索引

图片23

==关于频率的更多缩写==

图片24

==在DataFrame中使用时间序列==

index=pd.date_range("20170101",periods=10)

df = pd.DataFrame(np.random.rand(10),index=index)

回到最开始的911数据的案例中,我们可以使用pandas提供的方法把时间字符串转化为时间序列

df["timeStamp"] = pd.to_datetime(df["timeStamp"],format="")

format参数大部分情况下可以不用写,但是对于pandas无法格式化的时间字符串,我们可以使用该参数,比如包含中文

那么问题来了:

我们现在要统计每个月或者每个季度的次数怎么办呢?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
from matplotlib import pyplot as plt
import pandas as pd
df = pd.read_csv('911.csv')
#显示所有列
pd.set_option('display.max_columns', None)
# #显示所有行
pd.set_option('display.max_rows', None)
print(df.info())
print(df.head())
# 将时间字符串转换为时间类型数据datetime64,以便进一步处理
print(pd.to_datetime(df['timeStamp']).head())
# 重新赋值df['timeStamp']
df['timeStamp'] = pd.to_datetime(df['timeStamp'])
# 将列timeStamp转换为行索引
df.set_index('timeStamp',inplace=True)
print(df.head())

# 统计出911数据中不同月份电话次数
count_by_month = df.resample('M').count()['title']
print(count_by_month)

_x = count_by_month.index
_y = count_by_month.values
print(_x)
print(_y)
_x = [i.strftime('%Y%m%d') for i in _x]
plt.figure(figsize=(20,8), dpi=80)
plt.plot(_x,_y)
# plt.plot(range(len(_x)),_y)
plt.xticks(_x,rotation=45)
plt.show()

17.pandas重采样

图片25

==示例==

1.统计出911数据中不同月份电话次数的变化情况

2.统计出911数据中不同月份不同类型的电话的次数的变化情况

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
from matplotlib import pyplot as plt
import pandas as pd,numpy as np
df = pd.read_csv('911.csv')
# 重新赋值df['timeStamp']
df['timeStamp'] = pd.to_datetime(df['timeStamp'])
#添加列,表示分类
temp_list = df["title"].str.split(": ").tolist()
cate_list = [i[0] for i in temp_list]
# 创建列
df["cate"] = pd.DataFrame(np.array(cate_list).reshape((df.shape[0],1)))
# 将时间列转化为索引
df.set_index("timeStamp",inplace=True)
print(df.head(1))
dk = df.groupby('cate')
print(dk)
plt.figure(figsize=(20, 8), dpi=80)
for group_name,group_data in dk:
print(group_name,group_data)
# 对不同的分类都进行绘图
count_by_month = group_data.resample("M").count()["title"]
# 画图
_x = count_by_month.index
print(_x)
_y = count_by_month.values
print(_y)
_x = [i.strftime("%Y%m%d") for i in _x]

plt.plot(range(len(_x)), _y, label=group_name)

plt.xticks(range(len(_x)), _x, rotation=45)
plt.legend(loc="best")
plt.show()

现在我们有北上广、深圳、和沈阳5个城市空气质量数据,请绘制出5个城市的PM2.5随时间的变化情况

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# coding=utf-8
import pandas as pd
from matplotlib import pyplot as plt

file_path = "./PM2.5/BeijingPM20100101_20151231.csv"

df = pd.read_csv(file_path)
print(df.head())
print(df.info())
# 把分开的时间字符串通过periodIndex的方法转化为pandas的时间类型
period = pd.PeriodIndex(year=df["year"], month=df["month"], day=df["day"], hour=df["hour"], freq="H")
# 增加一列df["datetime"]
df["datetime"] = period
print(df.head(10))
#
# 把datetime 设置为索引
df.set_index("datetime", inplace=True)
#
# 进行降采样,如果按日来排序,数据图不好看,按月份太稀疏,按日太绸
df = df.resample("7D").mean()
print(df.head())
# 处理缺失数据,删除缺失数据
print(df["PM_US Post"])
# dropna()该函数主要用于滤除缺失数据。
# 如果是Series,则返回一个仅含非空数据和索引值的Series,默认丢弃含有缺失值的行。
# 美国数据
data = df["PM_US Post"].dropna() # 使用降采样后,会计算均值,这里再使用dropna()过滤空值意义不大
# 中国数据
data_china = df["PM_Nongzhanguan"]

print(data_china.head(100))
#画图

_x = data.index
_x = [i.strftime("%Y%m%d") for i in _x]
# 取中国PM2.5数据
_x_china = [i.strftime("%Y%m%d") for i in data_china.index]
print(len(_x_china),len(_x_china))
_y = data.values
_y_china = data_china.values


plt.figure(figsize=(20,8),dpi=80)

plt.plot(range(len(_x)),_y,label="US_POST",alpha=0.7)
plt.plot(range(len(_x_china)),_y_china,label="CN_POST",alpha=0.7)

plt.xticks(range(0,len(_x_china),10),list(_x_china)[::10],rotation=45)

plt.legend(loc="best")

plt.show()