本内容来自《跟着迪哥学Python数据分析与机器学习实战》,该篇博客将其内容进行了整理,加上了自己的理解,所做小笔记。若有侵权,联系立删。
迪哥说以下的许多函数方法都不用死记硬背,多查API多看文档,确实,跟着迪哥混就完事了~~~
Pandas官网API
以下代码段均在Jupyter Notebook下进行运行操作
每天过一遍,腾讯阿里明天见~
Pandas工具包是专门用作数据处理和分析的,其底层的计算其实都是由Numpy来完成。
一、数据预处理
Ⅰ,数据读取
将下载好的泰坦尼克号成员名单数据集放到Jupyter Notebook同级目录下
需要指定好数据的路径,至于read_csv()函数,默认读取的数据格式是.csv,也就是以逗号为分隔符的数据集
df.head(10)表示展示其中前10条数据
df.tail(10)表示展示其中后10条数据
import pandas as pd
import numpy as np
df = pd.read_csv('titanic.csv')#指定数据集路径
df.head(10)#不填参数默认展示前5条
df.tail(10)#不填参数默认展示后5条
Ⅱ,DataFrame结构
df是Pandas工具包中最常见的基础结构
pandas.core.frame.DataFrame可以把它当作是一个二维矩阵结构
基本上读取数据返回的都是DataFrame结构
df.info()函数用于打印当前读取数据的部分信息,包括数据样本规模、每列特征类型与个数、整体的内存占用等
df.info()
"""
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 891 entries, 0 to 890
Data columns (total 12 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 PassengerId 891 non-null int64
1 Survived 891 non-null int64
2 Pclass 891 non-null int64
3 Name 891 non-null object
4 Sex 891 non-null object
5 Age 714 non-null float64
6 SibSp 891 non-null int64
7 Parch 891 non-null int64
8 Ticket 891 non-null object
9 Fare 891 non-null float64
10 Cabin 204 non-null object
11 Embarked 889 non-null object
dtypes: float64(2), int64(5), object(5)
memory usage: 83.7+ KB
"""
返回索引
df.index
"""
RangeIndex(start=0, stop=891, step=1)
"""
拿到每一列特征的信息
df.columns
"""
Index(['PassengerId', 'Survived', 'Pclass', 'Name', 'Sex', 'Age', 'SibSp',
'Parch', 'Ticket', 'Fare', 'Cabin', 'Embarked'],
dtype='object')
"""
返回每一列特征的类型,其中object为python中的字符串类型
df.dtypes
"""
PassengerId int64
Survived int64
Pclass int64
Name object
Sex object
Age float64
SibSp int64
Parch int64
Ticket object
Fare float64
Cabin object
Embarked object
dtype: object
"""
返回数据矩阵
df.values
"""
array([[1, 0, 3, ..., 7.25, nan, 'S'],
[2, 1, 1, ..., 71.2833, 'C85', 'C'],
[3, 1, 3, ..., 7.925, nan, 'S'],
...,
[889, 0, 3, ..., 23.45, nan, 'S'],
[890, 1, 1, ..., 30.0, 'C148', 'C'],
[891, 0, 3, ..., 7.75, nan, 'Q']], dtype=object)
"""
Ⅲ,数据索引
通过指定名字来取其中某一列指标
age = df['Age']
age[0:5]
"""
0 22.0
1 38.0
2 26.0
3 35.0
4 35.0
Name: Age, dtype: float64
"""
在读取数据时,read_csv()函数会默认把读取数据中的第一行当作列名
对其中的数值进行操作
age.values[0:5]
"""
array([22., 38., 26., 35., 35.])
"""
可以将姓名设置为索引,也可以自己设置其他索引。
df = df.set_index('Name')
df.head(6)
如果想得到某个乘客的特征信息,可以直接通过姓名来查找
age = df['Age']
age['Allen, Mr. William Henry']
"""
35.0
"""
要通过索引来取某一部分具体数据,指定具体的几列
df[['Age','Fare']][0:5]
.iloc():用位置找数据
第一列是用户的信息特征,第二列是信息所对应的数据
df.iloc[0]
"""
PassengerId 1
Survived 0
Pclass 3
Sex male
Age 22
SibSp 1
Parch 0
Ticket A/5 21171
Fare 7.25
Cabin NaN
Embarked S
Name: Braund, Mr. Owen Harris, dtype: object
"""
使用切片获取一部分数据
df.iloc[0:5]
也可以指定特征
df.iloc[0:5,1:3]
.loc():用标签找数据
以名字为索引,指定名字来获取该人的数据信息
df = df.set_index('Name')
df.loc['Heikkinen, Miss. Laina']
"""
PassengerId 3
Survived 1
Pclass 3
Sex female
Age 26
SibSp 0
Parch 0
Ticket STON/O2. 3101282
Fare 7.925
Cabin NaN
Embarked S
Name: Heikkinen, Miss. Laina, dtype: object
"""
取当前数据的某一列信息
df.loc['Heikkinen, Miss. Laina','Fare']
"""
7.925
"""
选择多个样本,例如从狗蛋儿到王二麻子之间的所有人信息
df.loc['Heikkinen, Miss. Laina':'Allen, Mr. William Henry',:]
可以对数据进行赋值
df.loc['Heikkinen, Miss. Laina','Fare'] = 1000
df.iloc[0:5]
bool类型同样可以当作索引
筛选Fare大于40的旅客信息,因为前面以及将姓名作为索引了,故这里只展示姓名信息
df['Fare'] > 40
"""
Name
Braund, Mr. Owen Harris False
Cumings, Mrs. John Bradley (Florence Briggs Thayer) True
Heikkinen, Miss. Laina True
Futrelle, Mrs. Jacques Heath (Lily May Peel) True
Allen, Mr. William Henry False
...
Montvila, Rev. Juozas False
Graham, Miss. Margaret Edith False
Johnston, Miss. Catherine Helen "Carrie" False
Behr, Mr. Karl Howell False
Dooley, Mr. Patrick False
Name: Fare, Length: 891, dtype: bool
"""
展示Fare大于40的前五个旅客所有信息
df[df['Fare'] > 40] [0:5]
筛选前五个性别是男的旅客全部信息
df[df['Sex'] == 'male'] [0:5]
计算所有男性旅客的平均年龄
df.loc[df['Sex'] == 'male','Age'].mean()
"""
30.72664459161148
"""
统计年龄超过70岁的旅客有几个
(df['Age']>70).sum()
"""
5
"""
Ⅳ,创建DataFrame
DataFrame是通过读取数据得到的
想展示某些信息,也可以自己创建
最简单的方法就是创建一个字典结构,其中key表示特征名字,value表示各个样本的实际值,然后通过pd.DataFrame()函数来创建
data = {'country':['China','America','India'],'population':[14,3,12]}
df_data = pd.DataFrame(data)
df_data
如果数据量过多,读取的数据不会全部显示,而是会隐藏部分数据,这时可以通过设置参数来控制显示结果
get_option可以查看默认显示的最大行数
pd.get_option('display.max_rows')
"""
60
"""
get_option可以查看默认最大显示的列数
pd.get_option('display.max_columns')
"""
20
"""
由于设置了display.max_rows=6,因此只显示其中6条数据,其余省略了
pd.set_option('display.max_rows',6)
pd.Series(index=range(0,100))
"""
0 NaN
1 NaN
2 NaN
..
97 NaN
98 NaN
99 NaN
Length: 100, dtype: float64
"""
如果数据特征稍微有点多,可以设置得更大一些
pd.set_option('display.max_columns',30)
pd.DataFrame(columns = range(0,30))
Ⅴ,Series操作
前面提到的操作对象都是DataFrame
Series简单来说,读取的数据都是二维的,也就是DataFrame
如果在数据中单独取某列数据,那就是Series格式了,相当于DataFrame是由Series组合起来得到的
创建Series
data = [5,22,10,14,12,6]
index = ['b','e','y','o','n','d']
s = pd.Series(data=data,index=index)
s
"""
b 5
e 22
y 10
o 14
n 12
d 6
dtype: int64
"""
通过索引查询操作与DataFrame是一样的
查看key为’b’所对应的数据的值
s.loc['b']
"""
5
"""
查看下标为1的数据的值
s.iloc[1]
"""
22
"""
改值操作
s1 = s.copy()
s1['o'] = 100
s1
"""
b 5
e 22
y 10
o 100
n 12
d 6
dtype: int64
"""
也可以使用replace()函数
replace()函数的参数中多了一项inplace
如果设置inplace=False,就是不将结果赋值给变量,只相当于打印操作
如果设置inplace=True,就是直接在数据中执行实际变换,而不仅是打印操作
s1.replace(to_replace=100,value=101,inplace=True)
s1
"""
b 5
e 22
y 10
o 101
n 12
d 6
dtype: int64
"""
以改索引操作
s1.index
"""
Index(['b', 'e', 'y', 'o', 'n', 'd'], dtype='object')
"""
方法一
s1.index = ['b', 'e', 'Y', 'o', 'n', 'd']
s1
"""
b 5
e 22
Y 10
o 101
n 12
d 6
dtype: int64
"""
方法二
s1.rename(index = {'b':'B'},inplace=True)
s1
"""
B 5
e 22
Y 10
o 101
n 12
d 6
dtype: int64
"""
增操作
data = [55,99]
index = ['y','q']
s2 = pd.Series(data=data,index=index)
s2
"""
y 55
q 99
dtype: int64
"""
s3 = s1.append(s2)
s3
"""
B 5
e 22
Y 10
o 101
n 12
d 6
y 55
q 99
dtype: int64
"""
s3['y'] = 500
s3
"""
B 5
e 22
Y 10
o 101
n 12
d 6
y 500
q 99
dtype: int64
"""
删操作
s1
"""
B 5
e 22
Y 10
o 101
n 12
d 6
dtype: int64
"""
del s1['e']
s1
"""
B 5
Y 10
o 101
n 12
d 6
dtype: int64
"""
也可以直接del选中数据的索引进行删除
s1.drop(['n','d'],inplace=True)
s1
"""
B 5
Y 10
o 101
dtype: int64
"""
二、数据分析
Ⅰ,统计分析
在DataFrame中对数据进行计算跟Numpy差不多,默认都是对整体进行操作
df = pd.DataFrame([[1,2,3],[7,4,1]],index=['a','b'],columns=['A','B','C'])
df
对数据求和
df.sum()#默认按列求和,即axis=0
"""
A 8
B 6
C 4
dtype: int64
"""
df.sum(axis=1)
"""
a 6
b 12
dtype: int64
"""
对数据求均值
df.mean()
"""
A 4.0
B 3.0
C 2.0
dtype: float64
"""
df.mean(axis=1)
"""
a 2.0
b 4.0
dtype: float64
"""
求数据的中位数
df.median()
"""
A 4.0
B 3.0
C 2.0
dtype: float64
"""
df.median(axis=1)
"""
a 2.0
b 4.0
dtype: float64
"""
求数据的最大值
df.max()
"""
A 7
B 4
C 3
dtype: int64
"""
df.max(axis=1)
"""
a 3
b 7
dtype: int64
"""
求数据的最小值
df.min()
"""
A 1
B 2
C 1
dtype: int64
"""
df.min(axis=1)
"""
a 1
b 1
dtype: int64
"""
使用describe()函数,既可以得到各项统计指标,也可以观察数据是否存在
df.describe()
下面开始对泰坦尼克号旅客信息进行操作
df = pd.read_csv('titanic.csv')
df.describe()
协方差矩阵
df.cov()
相关系数
df.corr()
统计某一列各个属性的比例情况,需要使用value_counts()函数
统计性别这一列中所有属性的个数
df['Sex'].value_counts()
"""
male 577
female 314
Name: Sex, dtype: int64
"""
指定顺序,个数少的排在前面,即从小到大排序
df['Sex'].value_counts(ascending=True)
"""
female 314
male 577
Name: Sex, dtype: int64
"""
像年龄这种离散型指标就显得不太好处理
df['Age'].value_counts(ascending=True)
"""
0.42 1
23.50 1
66.00 1
70.50 1
55.50 1
..
30.00 25
19.00 25
18.00 26
22.00 27
24.00 30
Name: Age, Length: 88, dtype: int64
"""
把所有年龄这一列中的所有数据平均分为为5组,因为ascending=True故从小到大排序
df['Age'].value_counts(ascending=True,bins=5)
"""
(64.084, 80.0] 11
(48.168, 64.084] 69
(0.339, 16.336] 100
(32.252, 48.168] 188
(16.336, 32.252] 346
Name: Age, dtype: int64
"""
创建一个年龄数组ages,然后指定4个判断值,接下来就用这4个值把数据分成(0,10],(10,15],(15,30]这三组,返回的结果分别表示当前年龄属于哪组。
ages = [15,18,2,4,22,13,10,26,29]
bins = [0,10,15,30]
bins_res = pd.cut(ages,bins)
bins_res
"""
[(10, 15], (15, 30], (0, 10], (0, 10], (15, 30], (10, 15], (0, 10], (15, 30], (15, 30]]
Categories (3, interval[int64]): [(0, 10] < (10, 15] < (15, 30]]
"""
可以打印其默认标签值,当前分组结果
bins_res.codes
"""
array([1, 2, 0, 0, 2, 1, 0, 2, 2], dtype=int8)
"""
各组总人数
pd.value_counts(bins_res)
"""
(15, 30] 4
(0, 10] 3
(10, 15] 2
dtype: int64
"""
分为四组
pd.cut(ages,[0,10,30,50,80])
"""
[(10, 30], (10, 30], (0, 10], (0, 10], (10, 30], (10, 30], (0, 10], (10, 30], (10, 30]]
Categories (4, interval[int64]): [(0, 10] < (10, 30] < (30, 50] < (50, 80]]
"""
自己给这四组进行定义标签
group_names = ['baby','teenage','adult','older']
pd.value_counts(pd.cut(ages,[0,10,30,50,80],labels=group_names))
"""
teenage 6
baby 3
older 0
adult 0
dtype: int64
"""
Ⅱ,pivot数据透视表
随便创建点数据,其中Category表示把钱花在什么用途上(如交通运输、家庭、娱乐等费用),Month表示统计月份,Amount表示实际的花费。
example = pd.DataFrame({'Month':["January","January","January","January","February","February","February","February","March","March","March","March"],
'Category':["Transportation","Grocery","Household","Entertainment","Transportation","Grocery","Household","Entertainment","Transportation","Grocery","Household","Entertainment"],
'Amount':[74.,235.,175.,100.,115.,240.,225.,125.,90.,26.,200.,120.]})
example
统计的每个月花费在各项用途上的金额分别是多少
example_pivot = example.pivot(index='Category',columns="Month",values="Amount")
example_pivot
这几个月中每项花费的总额
example_pivot.sum(axis=1)
"""
Category
Entertainment 345.0
Grocery 501.0
Household 600.0
Transportation 279.0
dtype: float64
"""
每个月所有花费的总额
example_pivot.sum(axis=0)
"""
Month
February 705.0
January 584.0
March 436.0
dtype: float64
"""
使用泰坦尼克号旅客信息来进行实操
Pclass表示船舱等级,Fare表示船票的价格
按乘客的性别分别统计各个舱位购票的平均价格
index指定了按照什么属性来统计,columns指定了统计哪个指标,values指定了统计的实际指标值是什么
df = pd.read_csv('titanic.csv')
df.pivot_table(index='Sex',columns='Pclass',values='Fare')
平均值相当于是默认值,如果想指定最大值或者最小值,还需要额外指定aggfunc来明确结果的含义
df.pivot_table(index='Sex',columns='Pclass',values='Fare',aggfunc='max')
统计各个船舱等级的人数
df.pivot_table(index='Sex',columns='Pclass',values='Fare',aggfunc='count')
首先按照年龄将乘客分成两组:成年人和未成年人。再对这两组旅客分别统计不同性别的人的平均获救可能性
df['Underaged'] = df['Age'] <= 18
df.pivot_table(index='Underaged',columns='Sex',values='Survived',aggfunc='mean'
Ⅲ,groupby操作
df = pd.DataFrame({'key':['A','B','C','A','B','C','A','B','C'],
'data':[0,5,10,5,10,15,10,15,20]})
df
统计各个key中对应的data数值总和,一般方法
for key in['A','B','C']:
print(key,df[df['key'] == key].sum())
"""
A key AAA
data 15
dtype: object
B key BBB
data 30
dtype: object
C key CCC
data 45
dtype: object
"""
统计各个key中对应的data数值总和,groupby
df.groupby('key').sum()
统计各个key中对应的data均值,groupby
df.groupby('key').aggregate(np.mean)
使用泰坦尼克号旅客数据集,按照不同性别统计其年龄的平均值
df = pd.read_csv('titanic.csv')
df.groupby('Sex')['Age'].mean()
"""
Sex
female 27.915709
male 30.726645
Name: Age, dtype: float64
"""
groupby()函数中还有很多参数可以设置
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
观察groupby某一列(A列)后结果的数量
grouped = df.groupby('A')
grouped.count()
观察groupby某一列(A、B列)后结果的数量
grouped = df.groupby(['A','B'])
grouped.count()
求和
grouped = df.groupby(['A','B'])
grouped.aggregate(np.sum)
加入索引,按照传入参数的顺序来指定
grouped = df.groupby(['A','B'],as_index=False)
grouped.aggregate(np.sum)
使用describe()方法来展示前5条统计信息
grouped.describe().head()
可以自己设置需要的统计指标
grouped = df.groupby('A')
grouped['C'].agg([np.sum,np.mean,np.std])
在groupby操作中还可以指定操作的索引(也就是level)
arrays = [['bar','bar','baz','baz','foo','foo','qux','qux'],
['one','two','one','two','one','two','one','two']]
index = pd.MultiIndex.from_arrays(arrays,names=['first','second'])
index
"""
MultiIndex([('bar', 'one'),
('bar', 'two'),
('baz', 'one'),
('baz', 'two'),
('foo', 'one'),
('foo', 'two'),
('qux', 'one'),
('qux', 'two')],
names=['first', 'second'])
"""
光有索引还不够,还需要具体数值
s = pd.Series(np.random.randn(8),index=index)
s
"""
first second
bar one 0.334041
two -0.370639
baz one 0.932589
two -1.047145
foo one -1.004788
two -0.197581
qux one -1.114047
two 1.019581
dtype: float64
"""
通过level参数可以指定以哪项为索引进行计算
当level为0时,设置名为first的索引
当level为1时,设置名为second的索引
grouped = s.groupby(level=0)
grouped.sum()
"""
first
bar -0.036598
baz -0.114556
foo -1.202369
qux -0.094466
dtype: float64
"""
grouped = s.groupby(level=1)
grouped.sum()
"""
second
one -0.852205
two -0.595784
dtype: float64
"""
如果觉得指定一个数值不够直观,也可以直接用具体名字,结果相同
grouped = s.groupby(level='first')
grouped.sum()
"""
first
bar -0.036598
baz -0.114556
foo -1.202369
qux -0.094466
dtype: float64
"""
三、常用函数操作
Ⅰ,Merge操作
先创建两个DataFrame,key值相同
left = pd.DataFrame({'key':['K0','K1','K2','K3'],
'A':['A0','A1','A2','A3'],
'B':['B0','B1','B2','B3']})
left
right = pd.DataFrame({'key':['K0','K1','K2','K3'],
'C':['C0','C1','C2','C3'],
'D':['D0','D1','D2','D3']})
right
按照key列把两份数据整合在一起,这里的key值是一样的
res = pd.merge(left,right,on='key')
res
再创建两个DataFrame,key1列和key2列的前3行都相同,但是第4行的值不同
left = pd.DataFrame({'key1':['K0','K1','K2','K3'],
'key2':['K0','K1','K2','K3'],
'A':['A0','A1','A2','A3'],
'B':['B0','B1','B2','B3']})
left
right = pd.DataFrame({'key1':['K0','K1','K2','K3'],
'key2':['K0','K1','K2','K4'],
'C':['C0','C1','C2','C3'],
'D':['D0','D1','D2','D3']})
right
前3行相同的都组合在一起了,但是第4行却被直接抛弃了
res = pd.merge(left,right,on=['key1','key2'])
res
额外设置一个how参数,将抛弃的第4行给显示
res = pd.merge(left,right,on=['key1','key2'],how='outer')
res
还可以加入详细的组合说明,指定indicator参数为True即可
res = pd.merge(left,right,on=['key1','key2'],how='outer',indicator=True)
res
单独设置只考虑左边数据或者只考虑右边数据
res = pd.merge(left,right,how='left')
res
res = pd.merge(left,right,how='right')
res
Ⅱ,排序操作
创建一个DataFrame
data = pd.DataFrame({'group':['a','a','a','b','b','b','c','c','c'],
'data':[0,5,22,10,14,99,98,19,7]})
data
可以指定升序或者降序,并且还可以指定按照多个指标排序
首先对group列按照降序进行排列,在此基础上保持data列是升序排列,其中by参数用于设置要排序的列,ascending参数用于设置升降序
data.sort_values(by=['group','data'],ascending=[False,True],inplace=True)
data
Ⅲ,缺失值处理
创建一组数据用乘法来创建一组有重复部分的数据
data = pd.DataFrame({'k1':['one']*3 + ['two']*4,
'k2':[3,2,1,5,5,10,14]})
data
使用drop_duplicates()函数去掉多余的数据
data.drop_duplicates()
只考虑某一列的重复情况,其他全部舍弃
data.drop_duplicates(subset='k1')
直接指定新的列名或者使用assign()函数要往数据中添加新的列
df = pd.DataFrame({'data1':np.random.randn(5),'data2':np.random.randn(5)})
df1 = df.assign(ration=df['data1']/df['data2'])
df1
数据处理过程中经常会遇到缺失值,Pandas中一般用NaN来表示(Not a Number)
df = pd.DataFrame([range(3),[0,np.nan,0],[0,0,np.nan],range(3)])
df
通过isnull()函数判断所有缺失情况
df.isnull()
输出某列是否存在缺失值,其中.any()函数相当于只要有一个缺失值就意味着存在缺失情况
df.isnull().any()
"""
0 False
1 True
2 True
dtype: bool
"""
可以自己指定检查的维度
df.isnull().any(axis=1)
"""
0 False
1 True
2 True
3 False
dtype: bool
"""
缺失值填充,fillna()函数可以对缺失值进行填充,这里只选择一个数值,实际中更常使用的是均值、中位数,具体情况具体分析
df.fillna(5)
Ⅳ,apply自定义函数
首先定义一个映射函数
data = pd.DataFrame({'food':['A1','A2','B1','B2','B3','C1','C2'],
'data':[1,4,7,8,5,2,3]})
data
apply()函数使用,需要先写好要执行操作的函数,接下来直接调用即可,相当于对数据中所有样本都执行这样的操作
def food_map(series):
if series['food'] == 'A1':
return 'A'
elif series['food'] == 'A2':
return 'A'
elif series['food'] == 'B1':
return 'B'
elif series['food'] == 'B2':
return 'B'
elif series['food'] == 'B3':
return 'B'
elif series['food'] == 'C1':
return 'C'
elif series['food'] == 'C2':
return 'C'
data['food_map'] = data.apply(food_map,axis='columns')
data
使用泰坦尼克号旅客信息运用apply()函数
统计每列的缺失值个数,写好自定义函数之后依旧调用apply()函数,这样每列特征的缺失值个数就统计出来了
titanic = pd.read_csv('titanic.csv')
def nan_count(columns):
columns_null = pd.isnull(columns)
null = columns[columns_null]
return len(null)
columns_null_count = titanic.apply(nan_count)
columns_null_count
"""
PassengerId 0
Survived 0
Pclass 0
Name 0
Sex 0
Age 177
SibSp 0
Parch 0
Ticket 0
Fare 0
Cabin 687
Embarked 2
dtype: int64
"""
统计一下每一位乘客是否是成年人
def is_minor(row):
if row['Age'] < 18:
return True
else:
return False
minors = titanic.apply(is_minor,axis=1)
minors
"""
0 False
1 False
2 False
3 False
4 False
...
886 False
887 False
888 False
889 False
890 False
Length: 891, dtype: bool
"""
Ⅴ,时间操作
创建一个时间戳
ts = pd.Timestamp('2022-5-3')
ts
"""
Timestamp('2022-05-03 00:00:00')
"""
ts.month
"""
5
"""
ts.day
"""
3
"""
ts + pd.Timedelta('7 days')
"""
Timestamp('2022-05-10 00:00:00')
"""
s = pd.Series(['2022-5-3 21:40:10','2022-5-4 10:14:05','2022-5-5 05:22:06'])
s
"""
0 2022-5-3 21:40:10
1 2022-5-4 10:14:05
2 2022-5-5 05:22:06
dtype: object
"""
ts = pd.to_datetime(s)
ts
"""
0 2022-05-03 21:40:10
1 2022-05-04 10:14:05
2 2022-05-05 05:22:06
dtype: datetime64[ns]
"""
ts.dt.hour
"""
0 21
1 10
2 5
dtype: int64
"""
ts.dt.weekday
"""
0 1
1 2
2 3
dtype: int64
"""
知道数据的采集时间,并且每条数据都是固定时间间隔保存
pd.Series(pd.date_range(start='2022-5-3',periods=14,freq='12H'))
"""
0 2022-05-03 00:00:00
1 2022-05-03 12:00:00
2 2022-05-04 00:00:00
3 2022-05-04 12:00:00
4 2022-05-05 00:00:00
5 2022-05-05 12:00:00
6 2022-05-06 00:00:00
7 2022-05-06 12:00:00
8 2022-05-07 00:00:00
9 2022-05-07 12:00:00
10 2022-05-08 00:00:00
11 2022-05-08 12:00:00
12 2022-05-09 00:00:00
13 2022-05-09 12:00:00
dtype: datetime64[ns]
"""
以时间特征为索引,可以将parse_dates参数设置为True
flowdata数据集
data = pd.read_csv('flowdata.csv',index_col=0,parse_dates=True)
data
有了索引后,就可以用它来取数据
data[pd.Timestamp('2012-01-01 09:00'):pd.Timestamp('2012-01-01 19:00')]
取2013年的数据
也用data[‘2012-01’:‘2012-03’]指定具体月份,或者更细致一些,在小时上继续进行判断
例如:data[(data.index.hour>8)&(data.index.hour<12)]
data['2013']
resample重采样
原始数据中每天都有好几条数据,统计每天的平均指标
data.resample('D').mean().head()
按3天为一个周期进行统计
data.resample('3D').mean().head()
按月进行统计
data.resample('M').mean().head()
Ⅵ,绘图操作
%matplotlib inline#在Jupyter Notebook中使用绘图操作需要先执行此命令
df = pd.DataFrame(np.random.randn(10,4).cumsum(0),index=np.arange(0,100,10),columns=['A','B','C','D'])
df.plot()
"""
<AxesSubplot:>
"""
同时展示两个图表,用到子图
import matplotlib.pyplot as plt
fig,axes = plt.subplots(2,1)#指定子图为2行1列
data = pd.Series(np.random.rand(16),index=list('abcdefghijklmnop'))
data.plot(ax=axes[0],kind='bar')#axes[0]为第一个子图
data.plot(ax=axes[1],kind='barh')#axes[1]为第二个子图
"""
<AxesSubplot:>
"""
指定绘图的种类,例如条形图、散点图等
df = pd.DataFrame(np.random.rand(6,4),index=['one','two','three','four','five','six'],
columns=pd.Index(['A','B','C','D'],name='Beyond'))
df
df.plot(kind='bar')
"""
<AxesSubplot:>
"""
macro = pd.read_csv('macrodata.csv')
macro.plot.scatter('quarter','realgdp')
"""
<AxesSubplot:xlabel='quarter', ylabel='realgdp'>
"""
四、大数据处理技巧
Ⅰ,数值类型转换
读取一个稍大数据集,特征比较多,一共有161列,目标就是尽可能减少占用的内存
gl = pd.read_csv('game_logs.csv')
gl.head()
数据样本有171907个
gl.shape
"""
(171907, 161)
"""
deep表示要详细的展示当前数据所占用的内存
输出结果显示这份数据读取进来后占用859.4 MB内存,数据类型主要有3种
float64类型有77个特征,int64类型有6个特征,object类型有78个特征
gl.info(memory_usage='deep')
"""
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 171907 entries, 0 to 171906
Columns: 161 entries, date to acquisition_info
dtypes: float64(77), int64(6), object(78)
memory usage: 859.4 MB
"""
计算一下各种类型平均占用内存
循环中会遍历3种类型,通过select_dtypes()函数选中属于当前类型的特征
计算其平均占用内存,最后转换成MB
很显然,float64类型和int64类型平均占用内存差不多,object类型占用的内存最多
for dtype in ['float64','int64','object']:
selected_dtype = gl.select_dtypes(include=[dtype])
mean_usage_b = selected_dtype.memory_usage(deep=True).mean()
mean_usage_mb = mean_usage_b/1024**2
print('avg memory:',dtype,mean_usage_mb)
"""
avg memory: float64 1.294733194204477
avg memory: int64 1.1242000034877233
avg memory: object 9.500870656363572
"""
接着,需要分类型对数据进行处理
首先处理一下数值型
输出结果分别打印了int8~int64可以表示的数值取值范围
int8和int16能表示的数值范围有点儿小,一般不用
int32看起来范围足够大了,基本任务都能满足
int64能表示的就更多了
int_types = ['int8','int16','int32','int64']
for it in int_types:
print(np.iinfo(it))
"""
Machine parameters for int8
---------------------------------------------------------------
min = -128
max = 127
---------------------------------------------------------------
Machine parameters for int16
---------------------------------------------------------------
min = -32768
max = 32767
---------------------------------------------------------------
Machine parameters for int32
---------------------------------------------------------------
min = -2147483648
max = 2147483647
---------------------------------------------------------------
Machine parameters for int64
---------------------------------------------------------------
min = -9223372036854775808
max = 9223372036854775807
---------------------------------------------------------------
"""
将数据集中所有int64类型转换成int32类型
def mem_usage(pandas_obj):
if isinstance(pandas_obj,pd.DataFrame):#计算DataFrame和Series类型数据,如果包含多列就求其总和,如果只有一列,那就是它自身
usage_b = pandas_obj.memory_usage(deep=True).sum()
else:
usage_b = pandas_obj.memory_usage(deep=True)
usage_mb = usage_b/1024**2
return '{:03.2f} MB'.format(usage_mb)
gl_int = gl.select_dtypes(include=['int64'])#select_dtypes(include=['int64'])表示此时要处理的是全部int64格式数据
coverted_int = gl_int.apply(pd.to_numeric,downcast='integer')#进行向下转换
gl_int
coverted_int
数据集所有数据类型都转换为int64时,int类型数据所占内存空间为7.87MB
向下转换之后,程序已经自动地选择了合适类型,int类型数据内存占有量为1.80MB
其中mem_usage()函数的主要功能就是计算传入数据的内存占用量
print(mem_usage(gl_int))
print(mem_usage(coverted_int))
"""
7.87 MB
1.80 MB
"""
向下转换程序已经自动地选择了合适类型
所有数据类型都转换为float64时,float类型数据内存占用100.99MB
向下转换之后,float类型数据内存占有量为50.49MB
内存节约了正好一半
通常在数据集中float类型多一些,如果对其进行合适的向下转换,基本上能节省一半内存
gl_float = gl.select_dtypes(include=['float64'])
converted_float = gl_float.apply(pd.to_numeric,downcast='float')
print(mem_usage(gl_float))
print(mem_usage(converted_float))
"""
100.99 MB
50.49 MB
"""
Ⅱ,属性类型转换
object类型(字符串)占用内存最多,各列object类型的特征如下
count表示数据中每一列特征的样本个数(有些存在缺失值)
unique表示不同属性值的个数(例如day_of_week列表示当前数据是星期几,所以只有7个不同的值;但是默认object类型会把出现的每一条样本数值都开辟一块内存区域,若星期一和星期二出现多次,它们只是一个字符串代表一种结果而已,共用一块内存就足够了。但是在object类型中却为每一条数据开辟了单独的一块内存)
故可以把object类型转换成category类型
gl_obj = gl.select_dtypes(include=['object']).copy()
gl_obj.describe()
把object类型转换成category类型
其中只有7种编码方式
dow = gl_obj.day_of_week
dow_cat = dow.astype('category')
dow_cat.head()
"""
0 Thu
1 Fri
2 Sat
3 Mon
4 Tue
Name: day_of_week, dtype: category
Categories (7, object): ['Fri', 'Mon', 'Sat', 'Sun', 'Thu', 'Tue', 'Wed']
"""
打印具体编码
无论打印多少条数据,其编码结果都不会超过7种,这就是category类型的特性
dow_cat.head(10).cat.codes
"""
0 4
1 0
2 2
3 1
4 5
5 4
6 2
7 2
8 1
9 5
dtype: int8
"""
将object类型转换成category类型,看下所占用内存空间情况
print(mem_usage(dow))
print(mem_usage(dow_cat))
"""
9.84 MB
0.16 MB
"""
converted_obj = pd.DataFrame()
for col in gl_obj.columns:
num_unique_values = len(gl_obj[col].unique())
num_total_values = len(gl_obj[col])
if num_unique_values / num_total_values < 0.5:#对object类型数据中唯一值个数进行判断,如果数量不足整体的一半(此时能共用的内存较多),就执行转换操作,如果唯一值过多,就没有必要执行此操作。
converted_obj.loc[:,col] = gl_obj[col].astype('category')
else:
converted_obj.loc[:,col] = gl_obj[col]
print(mem_usage(gl_obj))
print(mem_usage(converted_obj))
"""
750.57 MB
51.67 MB
"""