一、Pandas的使用

1.Pandas介绍

Pandas的主要应用包括:

  • 数据读取

  • 数据集成

  • 透视表

  • 数据聚合与分组运算

  • 分段统计

  • 数据可视化

Pandas的使用很灵活,最重要的两个数据类型是DataFrameSeries

对DataFrame最直观的理解是把它当成一个Excel表格文件,如下:

07b8f0dc5c2cb39bb492cce92997f2df.png

索引是从0开始的,也可以将某一行设置为index索引;
missing value为缺失值。

DataFrame的一列就是Series,Series可以转化为dataframe,调用方法函数to_frame()即可。

2.Pandas基本操作

Series的操作

Series的常见操作如下:

sis = Series([4,7,-5,3]
sis.to_frame()
sis.value_counts() # 统计每个唯一值的所有出现次数
sis.size
sis.shape
sis.count() # 返回非缺失值的数目
sis.min()
sis.max()
sis.median()
sis.std()
sis.sum()
sis.describe() # 返回摘要统计信息和几个分位数
sis.isnull() # 非空值
sis.fillna(0) # 用0来补充缺失值
#上述函数可以结合使用,如下
sis.isnull().sum()# 统计空值的个数

创建DataFrame

创建数据帧的语法如下:

pd.DataFrame( data=None, index=None, columns=None, dtype=None, copy=False)

参数说明:

  • data:可选数据类型,如:ndarray,series,map,lists,dict,constant和另一个DataFrame

  • index:行标签索引,缺省值np.arrange(n),不计入df列

  • columns:列标签索引,缺省值np.arrange(n),不计入df行

  • dtype:每列的数据类型

  • copy:默认值False,引用/复制数据

常见的几种创建数据帧的方式如下:

pd.set_option("max_columns",10,"max_rows",20) # 设置最大列数和最大行数
df = pd.DataFrame() # 空数据帧
df = pd.DataFrame(['a','b','c','d']) # 从一维列表创建
df = pd.DataFrame([['Alex',10],['Bob',12],['Clarke',13]], dtype=float) # 从二维列表创建,浮点型数字
df = pd.DataFrame({'Name':['Tom', 'Jack', 'Steve', 'Ricky'],'Age':[28,34,29,42]}) # 从字典创建,字典键默认为列标签

常见列操作

列名参与代数运算,表示列中每一个元素都与该数字进行同样的操作,如下:

movie = pd.read_csv('movie.csv')
imdb_score = movie['imdb_score']
imdb_score + 1 # 每一个列值加1
imdb_score * 2.5 # 给每一个列值乘2.5
imdb_score > 7 # 判断每一个列值是否大于7
imdb_score=="hello" # 判断是否等于字符串
imdb_score.floordiv(7) # imdb_score // 7,整数除法
imdb_score.gt(7) # imdb_score > 7
imdb_score.eq('James Cameron') # imdb_score == 'James Cameron'
type(imdb_score)
imdb_score.astype(int).mod(5) #每一个列值取模
sex_age = wl_melt['sex_age'].str.split(expand=True) # 对列使用字符串的多个方法

创建、删除列,通过[列名]来完成,如下:

movie["new_col"]=0
movie.insert(0, 'id', np.arange(len(movie))) # 插入新的列
movie["new_col"].all() #用来检测所有的布尔值都为True,用于比较两列是否相等

设置索引相关操作:

movie2 = movie.set_index('movie_title') # set_index()给行索引命名
movie2.reset_index() #复原索引
movie.rename(index=,columns=) # 其中参数值为键值对,键为旧值,值为新值。
movie.columns.tolist()
movie.columns=new_columns

特殊的列选择如下:

movie.get_dtype_counts() # 输出每种特定数据类型的列数
movie.select_dtypes(include=['int']).head() # 仅选择整数列
movie.filter(like='facebook').head() # like参数表示包含此字符串
movie.filter(regex='\d').head() # movie.filter支持正则表达式
movie.filter(items=['actor_1_name', 'asdf']) # 传入精确列名的列表

常见行操作

添加新行,用loc指定:

new_data_list = ['Aria', 1]
names.loc[4] = new_data_list
#等价于
names.loc[4] = ['Aria', 1]
names.append({'Name':'Aria', 'Age':1}, ignore_index=True) # append方法可以同时添加多行,此时要放在列表中
data_dict = bball_16.iloc[0].to_dict()
# keys参数可以给两个DataFrame命名,names参数可以重命名每个索引层
pd.concat(s_list, keys=['2016', '2017'], names=['Year', 'Symbol'])
pres_41_45['President'].value_counts()

DateFrame的基本操作

选取多个列时,参数用中括号[]括起来:

movie[['actor_1_name', 'actor_2_name',]] # 里面那个[]不要少

方法链:
用点记号.表示函数调用顺序的方式,要求为返回值必须为另外一个对象,如下:

person.drive('store').buy('food').drive('home').prepare('food').cook('food').serve('food').eat('food').cleanup('dishes

DataFrame中操作如下:

actor_1_fb_likes.fillna(0).astype(int).head()

对整个数据帧的操作:

movie.shape
movie.count()
movie.min() # 各列的最小值
movie.isnull().any().any() # 判断整个DataFrame有没有缺失值,方法是连着使用两个any
movie.isnull().sum() # 统计缺失值最主要方法是使用isnull方法
movie.sort_values('UGDS_HISP', ascending=False)# 按照某一列排序
movie.dropna(how='all')# 如果所有列都是缺失值,则将其去除

时间操作

pd.to_datetime能够将整个列表或一系列字符串或整数转换为时间戳

使用如下:

s = pd.Series(['12-5-2015', '14-1-2013', '20/12/2017', '40/23/2017'])
pd.to_datetime(s, dayfirst=True, errors='coerce')

时间戳操作如下:

pd.Timestamp(year=2012, month=12, day=21, hour=5,minute=10, second=8, microsecond=99)
pd.Timestamp('2016/1/10')
pd.Timestamp('2016-01-05T05:34:43.123456789')
pd.Timestamp(500) # 可以传递整数,表示距离1970-01-01 00:00:00.000000000的毫秒数
pd.to_datetime('2015-5-13') # 类似函数有pd.to_dataframe

to_timedelta()方法可以产生一个Timedelta对象,还可以和Timestamp互相加减,甚至可以相除返回一个浮点数,如下:

# to_timedelta产生Timedelta对象。
pd.Timedelta('12 days 5 hours 3 minutes 123456789 nanoseconds')
time_strings = ['2 days 24 minutes 89.67 seconds', '00:45:23.6']
pd.to_timedelta(time_strings)
# Timedeltas和Timestamps互相加减
pd.Timedelta('12 days 5 hours 3 minutes') * 2
ts = pd.Timestamp('2016-10-1 4:23:23.9')
ts.ceil('h') # Timestamp('2016-10-01 05:00:00')
td.total_seconds()

可以在导入的时候将时间列设为index,然后可以加快速度,时间支持部分匹配

# REPORTED_DATE设为了行索引,所以就可以进行智能Timestamp对象切分。
crime = crime.set_index('REPORTED_DATE')# .sort_index()
crime.loc['2016-05-12 16:45:00']
# 选取2012-06的数据
crime.loc[:'2012-06']
crime.loc['2016-05-12']
# 也可以选取一整月、一整年或某天的某小时
crime.loc['2016-05'].shape
crime.loc['2016'].shape
crime.loc['2016-05-12 03'].shape
crime.loc['Dec 2015'].sort_index()
# 用at_time方法选取特定时间
crime.at_time('5:47').head()
crime.plot(figsize=(16,4), )
crime_sort.resample('QS-MAR')['IS_CRIME', 'IS_TRAFFIC'].sum().head()

ded7f050221edad42eefb8d093c88272.png

3.Pandas进行数据分析

读取数据

college = pd.read_csv('college.csv')
employee = pd.read_csv('employee.csv')
college.head()
college.shape
display(college.describe(include=[np.number]).T) # 统计数值列,并进行转置

选择数据子集

直接在序列或数据帧之后加[]即可选择指定的数据集。

.iloc索引器只按整数位置进行选择,其工作方式与Python列表类似,区间为前闭后开;
.loc索引器只按索引标签进行选择,这与Python字典的工作方式类似,区间为后闭后开。
它们对行列均可以选择。

使用如下:

college.iloc[:, [4,6]].head( ) # 选取两列的所有的行
college.loc[:, ['WOMENONLY', 'SATVRMID']]
college.iloc[[60, 99, 3]].index.tolist() # .index.tolist()可以直接提取索引标签,生成一个列表
college.iloc[5, -4] # 整数索引
college.loc['The University of Alabama', 'PCTFLOAN'] # 标签索引
college[10:20:2] # 逐行读取
# Series也可以进行同样的切片
city = college['CITY']
city[10:20:2]

数据清洗

stack方法可以将每一行所有的列值转换为行值, unstack方法可以将其还原,如下:

state_fruit = pd.read_csv('state_fruit.csv', index_col=0)
state_fruit.stack() # 再使用reset_index()将结果转换为dataframe;给.columns赋值可以重命名列
# 也可以使用rename_axis给不同的行索引层级命名
state_fruit.stack().rename_axis(['state', 'fruit']).reset_index(name='weight')

用read_csv()方法只选取特定的列,指定uscols参数,如下:

usecol_func = lambda x: 'UGDS_' in x or x == 'INSTNM'
college = pd.read_csv('data/college.csv',usecols=usecol_func)

透视表pivot_table是一个很重要的概念,透视针对的对象是不同的列名,用法如下:

pandas.pivot_table(data, values=None, index=None, columns=None, aggfunc='mean', fill_value=None, margins=False, dropna=

其中参数:
index参数接受一个(或多个)不进行透视的列,其唯一值将放在索引中;
columns参数接受一个或多个列,该列将被透视,其唯一值将被生成列名;
values参数接受一个或多个要聚合的列;
aggfunc参数确定如何聚合values参数中的列。

拼接方法包括:
concat()提供了基于轴的连接灵活性(所有行或所有列);
append()是特殊情况的concat()( case(axis=0, join=‘outer’));
join()是基于索引(由set_index设置)的,其变量为['left', 'right', 'inner', 'couter'];
merge()是基于两个数据帧中的每一个特定列,这些列是像’left_on’、‘right_on’、'on’一样的变量。

布尔索引

布尔索引也叫布尔选择,通过提供布尔值值来选择行,这些布尔值通常存储在一个序列中,不同条件可以进行与或非(&、|、~)操作,但是在Python中,位运算符的优先级高于比较运算符,所以需要加括号。
如下:

criteria1 = movie.imdb_score > 8
criteria2 = movie.content_rating == 'PG-13'
criteria3 = (movie.title_year < 2000) | (movie.title_year >= 2010) # 括号不能少
final=criteria1 & criteria2 & criteria3
college[final] # 作为索引,直接选择值为True的行
employee.BASE_SALARY.between(80000, 120000) # 用between来选择
criteria = ~employee.DEPARTMENT.isin(top_5_depts) # 排除最常出现的5家单位
employee[criteria].head()

条件复杂时,可以采用数据帧的query方法,如下:

df.query('A > B') # 等价于df[df.A > df.B]
# 确定选取的部门和列
depts = ['Houston Police Department-HPD', 'Houston Fire Department (HFD)']
select_columns = ['UNIQUE_ID', 'DEPARTMENT', 'GENDER', 'BASE_SALARY']
qs = "DEPARTMENT in @depts and GENDER == 'Female' and 80000 <= BASE_SALARY <= 120000"
emp_filtered = employee.query(qs)
emp_filtered[select_columns].head()

对DataFrame的行调用msak()方法,使得所有满足条件的数据都消失:

criteria = criteria1 | criteria2
movie.mask(criteria).head()

对不满足条件的值进行替换,使用pandas的where语句。
如下:

s = pd.Series(range(5))
s.where(s > 1, 10)

group_by()的使用

通用数据分析模式:
将数据分解为独立的可管理块,独立地将函数应用于这些块,然后将结果组合在一起,
如下:

afe7eabf6c7fc097df8f0b0650b803fa.png

这需要使用到pandas提供的groupby()方法,可以对数据进行分组并调用聚合函数操作。

Pandas中,cut()方法用来把一组数据分割成离散的区间;
groupby()用于分组,并且可以对分组进行迭代,还可以使用分组运算方法即聚合函数agg() :针对某列使用agg()时进行不同的统计运算聚合size方法,同时聚合多种方法。

假设有数据:

import pandas as pd
df = pd.DataFrame({'A' : ['foo', 'bar', 'foo', 'bar',
'foo', 'bar', 'foo', 'foo'],
'B' : ['one', 'one', 'two', 'three',
'two', 'two', 'one', 'three'],
'C' : np.random.randn(8),
'D' : np.random.randn(8)})
df

即:

b4d219523631dfb9f078b55b202d20e8.png

分组迭代:

grouped = df.groupby('A')
for name, group in grouped:
print(name)
print(group)

打印:

bar
A B C D
1 bar one 0.991265 0.005204
3 bar three -0.791591 -0.576221
5 bar two -1.587038 0.634791
foo
A B C D
0 foo one -1.987942 -0.092403
2 foo two 0.786344 -0.575798
4 foo two 0.487330 -0.695639
6 foo one 0.937217 -1.001144
7 foo three -0.750302 1.495382

获取分组:

#获得一个分组get_group
grouped.get_group('bar')

显示:

adad49c34aab91750a1cf204c3030a26.png

使用聚合函数:

grouped = df.groupby('A')
grouped['C'].agg([np.sum, np.mean, np.std])

显示:

3c583695544f4ece454a8b2e4f193424.png

聚合函数统计个数:

df = pd.DataFrame({'Year' : ['2001', '2002', '2001', '2002',
'2001', '2002', '2001', '2002'],
'score' : ['primary', 'second', 'third', 'fourth',
'primary', 'second', 'fourth', 'third'],
'C' : [1,2,1,2,1,2,1,2],
'D' : np.random.randn(8)})
grouped = df.groupby('Year')
print (grouped['C'].agg(np.size))

打印:

Year
2001 4
2002 4
Name: C, dtype: int64

聚合函数中使用多种函数:

grouped = df.groupby('Year')
print (grouped['C'].agg([np.size,np.sum,np.mean]))

打印:

size  sum  mean
Year
2001 4 4 1
2002 4 8 2

更进一步操作:

score = lambda x: (x - x.mean())
print(df)
print('----------')
print(grouped['C'].agg(np.mean))
print('----------')
print (grouped['C'].transform(score))

打印:

   Year    score  C         D
0 2001 primary 1 -0.135237
1 2002 second 2 0.346450
2 2001 third 1 -0.004958
3 2002 fourth 2 2.722841
4 2001 primary 1 0.209729
5 2002 second 2 0.308275
6 2001 fourth 1 0.825608
7 2002 third 2 -0.569078
----------
Year
2001 1
2002 2
Name: C, dtype: int64
----------
0 0
1 0
2 0
3 0
4 0
5 0
6 0
7 0
Name: C, dtype: int64

进一步举例说明如下:

# 按照AIRLINE分组,使用agg方法,传入要聚合的列和聚合函数
flights.groupby('AIRLINE').agg({'ARR_DELAY':'mean'}).head()
# 或者要选取的列使用索引,聚合函数作为字符串传入agg
flights.groupby('AIRLINE')['ARR_DELAY'].agg('mean').head()
flights.groupby('AIRLINE')['ARR_DELAY'].mean().head()
#分组可以是多组,选取可以是多组,聚合函数也可以是多个,此时一一对应
flights.groupby(['AIRLINE', 'WEEKDAY'])['CANCELLED', 'DIVERTED'].agg(['sum',
'mean']).head(7)
#可以对同一列施加不同的函数
group_cols = ['ORG_AIR', 'DEST_AIR']
agg_dict = {'CANCELLED':['sum', 'mean', 'size'],
'AIR_TIME':['mean', 'var']}
flights.groupby(group_cols).agg(agg_dict).head()
#下面这个例子中,max_deviation是自定义的函数
def max_deviation(s):
std_score = (s - s.mean()) / s.std()
return std_score.abs().max()
college.groupby('STABBR')['UGDS'].agg(max_deviation).round(1).head()
grouped = college.groupby(['STABBR', 'RELAFFIL'])
grouped.ngroups# 用ngroups属性查看分组的数量
list(grouped.groups.keys())

需要用到的常见方法和含义如下:

方法含义aggregate()为每个组获取一个值filter()获取输入行的子集transform()为每个输入行获取新值apply()对某一列实施复杂操作

基本画图

Matplotlib提供了两种方法来作图:
面向过程和面向对象,推荐使用面向过程

Matplotlib常见画图过程如下:

x = [-3, 5, 7]
y = [10, 2, 5]
fig, ax = plt.subplots(figsize=(15,3))
ax.plot(x, y)
ax.set_xlim(0, 10)
ax.set_ylim(-3, 8)
ax.set_xlabel('X axis')
ax.set_ylabel('Y axis')
ax.set_title('Line Plot')
fig.suptitle('Figure Title', size=20, y=1.03)

pandas画图如下:

df = pd.DataFrame(index=['Atiya', 'Abbas', 'Cornelia', 'Stephanie', 'Monte'],data={'Apples':[20, 10, 40, 20, 50],'Oranges':[35, 40, 25, 19, 33]})
color = ['.2', '.7']
df.plot(kind='bar', color=color, figsize=(16,4))
fig, (ax1, ax2, ax3) = plt.subplots(1, 3, figsize=(16,4))
fig.suptitle('Two Variable Plots', size=20, y=1.02)
df.plot(kind='line', color=color, ax=ax1, )
df.plot(x='Apples', y='Oranges', kind='scatter', ax=ax2, )
df.plot(kind='bar', color=color, ax=ax3, )

如下:

fb42a2856c314a08517472a6c37d5193.png

还可以使用seaborn画图,如下:

import seaborn as sns
sns.heatmap(crime_table, cmap='Greys')
12

二、简单分析College数据

新建college_data目录,下放College.csv如下:

21ce5a623d7fa79ee38c40653c42d29c.png

如需获取数据、代码等相关文件进行测试学习,可以直接点击加QQ群 

b4cdf9d9d77aa558557a1f0c31d6e585.png

1136192749 在群文件夹Python数据分析实战中下载即可。

先读取和预览数据:

import pandas as pd
import numpy as np
from IPython.display import display
pd.options.display.max_columns = 50
college = pd.read_csv('College.csv')
college.head()

显示:

3b1cd3ca91d004023f0d407c90343bac.png

获取所有列名:

columns=college.columns
columns

打印:

Index(['Name', 'Private', 'Apps', 'Accept', 'Enroll', 'Top10perc', 'Top25perc', 'F.Undergrad', 'P.Undergrad', 'Outstate', 'Room.Board', 'Books', 'Personal', 'PhD', 'Terminal', 'S.F.Ratio', 'perc.alumni', 'Expend', 'Grad.Rate'], dtype='object')
1

选择数据子集:

print(college.iloc[:, [4,6]].head( )) # 选取4、6列的所有行
s1=college.loc[:, ['PhD', 'Books']]
s1.head()
1234

显示:

a94db2de58cc7953406b04eeeefa0972.png

一般在jupyter的一个cell中只默认输出最后一行的变量,要想输出前面行的数据,需要调用print()方法。

设置索引:

index=college.iloc[[60, 99, 3]].index.tolist() # .index.tolist()可以直接提取索引标签,生成一个列表
print(index)
college = college.set_index('Name',drop=False)
index2=college.iloc[[60, 99, 3]].index.tolist()
print(index2)
123456

打印:

[60, 99, 3]
['Bowdoin College', 'Centenary College of Louisiana', 'Agnes Scott College']
12

显然,在设置索引之前,索引默认为数字索引,在设置索引为Name之后,索引也相应发生变化。
其中,set_index()方法如果不设置drop参数,在将Name设为索引后,就将该列移除了,不能再重复执行这一行代码,否则会报错,设置drop参数为False后,设置Name为索引后也不会移除该列。

根据索引位置获取值如下:

col3 =college.loc['Albion College','Top10perc']
col3
12

打印:

37
1

这与数据中的值一致。

逐行读取如下:

s4=college[10:20:2]# 逐行读取,跨行读取
print(s4)
seriesapps = college['Apps']
seriesapps[1:10:2] # Series也可以进行同样的切片
1234

显示:

9ca3f48f290ecb63d8c0e5ef4b9a619b.png

其中,college[10:20:2]是对数据进行逐行读取,从第11行开始到21行,每隔一行读取一行数据。

查看索引如下:

college.index
1

打印:

Index(['Abilene', 'Adelphi University', 'Adrian College',
'Agnes Scott College', 'Alaska Pacific University', 'Albertson College',
'Albertus Magnus College', 'Albion College', 'Albright College',
'Alderson-Broaddus College',
...
'Winthrop University', 'Wisconsin Lutheran College',
'Wittenberg University', 'Wofford College',
'Worcester Polytechnic Institute', 'Worcester State College',
'Xavier University', 'Xavier University of Louisiana',
'Yale University', 'York College of Pennsylvania'],
dtype='object', name='Name', length=777)

完整操作过程如下:

未完待续!

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐