数据分析处理库(Pandas)
一、数据预处理
数据读取
pd.read_csv('数据所在的路径')
df.head(10) # 展示前10条数据,如果不填10,默认前5条
df.tail() # 展示后几条数据,默认后5条
DataFrame结构
df.info() # 用于打印当前读取数据的部分信息,包括数据样本规模、每列特征类型与个数、整体的内存占用等。
# 返回索引
df.index
# 拿到每一列特征的名字
df.columns
# 每一列的类型,其中object表示Python中的字符串
df.dtypes
# 直接取得数值矩阵
df.values
创建DataFrame
.iloc(): 用位置找数据
.loc(): 用标签找数据
DataFrame是通过读取数据得到的,如果想展示某些信息,也可以自己创建,最简单的方法是创建一个字典结构,其中key表示特征名字,value表示各个样本的实际值,然后通过pd.DataFrame()函数来创建。
data = {'country':['China', 'America', 'India'],
'population':[14, 3, 12]}
df_data = pd.DataFrame(data)
在用Notebook执行代码的时候,如果数据量过多,读取的数据不会全部显示,而是会隐藏部分数据,这时可以通过设置参数来控制显示结果。
下面是几个常用的设置:
# 注意这个是get,相当于显示当前设置的参数
pd.get_option('display.max_rows')
# 这回可是set,就是把最大显示限制成6个
pd.set_option('display.max_rows', 6)
# Series相当于二维数据中某一行或一列
pd.Series(index = range(0, 100))
# 默认最大显示的列数
pd.get_option('display.max_columns')
pd.set_option('display.max_columns', 30)
pd.DataFrame(columns = range(0, 30))
Series操作
Series是什么呢?简单来说,读取的数据都是二维的,也就是DataFrame;如果在数据中单独取某列数据,那就是Series格式了,相当于DataFrame是由Series组合起来的。
创建Series得方法:
data = [10, 11, 12]
index = ['a', 'b', 'c']
s = pd.Series(data = data, index = index)
改数值:
s1.replace(to_replace = 100, value = 101, inplace = True)
replace函数中的inplace项,如果设置inplace=False,就是不将结果赋值给变量,只相当于打印操作;如果设置inplace=True,就是直接在数据中执行实际变换,而不仅是打印操作。
不仅可以改数值,还可以改索引:
s1.rename(index = {'a':'A'},inplace = True)
增至操作:
data = [100,110]
index = ['h','k']
s2 = pd.Series(data = data,index = index)
s3 = s1.append(s2)
s3['j'] = 500
重置索引:在append函数中指定ignore_index = True
二、数据分析
统计分析
先用字典结构创建一个简单的DataFrame,既可以传入数据,也可以指定索引和列名:
df = pd.DataFrame([[1, 2, 3], [4, 5, 6]], index = ['a', 'b'], columns = ['A', 'B', 'C'])
# 默认是对每列计算所有样本操作结果,相当于df.sum(axis = 0)
df.sum()
# 也可以指定维度来设置计算方法
df.sum(axis = 1)
# 观察所有样本的情况
df.describe()
df = pd.read_csv('titanic.csv')
# 协方差矩阵
df.cov()
# 相关系数
df.corr()
# 统计该列所有属性的个数
df['Sex'].value_counts()
# 指定顺序,让少的排在前面
df['Sex'].value_counts(ascending = True)
# 指定划分成几个组
df['Age'].value_counts(ascending=True, bins=5)
# 用cut函数分组
ages = [15, 18, 20, 21, 22, 34, 41, 52, 63, 79]
bins = [10, 40, 80]
bins_res = pd.cut(ages, bins)
# 查看当前分组结果
bins_res.codes
# 各组总共人数
pd.value_counts(bins_res)
# 分成年轻人、中年人、老年人3组
pd.cut(ages, [10, 30, 50, 80])
# 可以自己定义标签
group_names = ['Yonth', 'Mille', 'Old']
pd.value_counts(pd.cut(ages, [10, 20, 50, 80], labels=group_names))
pivot数据透视表
df = pd.read_csv('titanic.csv')
df.pivot_table(index='Sex', columns='Pclass', values='Fare')
其中Pclass表示船舱等级,Fare表示船票的价格,这里表示按乘客的性别分别统计各个舱位购票的平均价格。index指定了按照什么属性来统计,columns指定了统计哪个指标,values指定了统计的实际指标值是什么。看起来各项参数都清晰明了。
# 统计各个船舱的最大票价,aggfunc来明确结果的含义。
df.pivot_table(index='Sex', columns='Pclass', values='Fare', aggfunc='max')
# 按照年龄将乘客分为成年组和未成年组。再对这两组乘客分别统计不同性别
# 的人的平均获救可能性
df['Deraged'] = df['Age'] > 18
df.pivot_table(index = 'Deraged', 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]})
如果想统计各个key中对应的data数值总和是多少,就可以用到groupby
df.groupby('key').sum()
继续用泰坦尼克号数据集,下面计算按照不同性别统计其年龄的平均值
df = pd.read_csv('titanic.csv')
df.groupby('Sex')['Age'].mean()
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)})
# 表示A在取不同key值时,B、C、D中样本的数量
grouped = df.groupby('A')
grouped.count()
也可以指定多个对象
grouped = df.groupby(['A', 'B'])
grouped.count()
指定好操作对象之后,通常还需要设置下计算或者统计的方法,比如求和:
grouped = df.groupby(['A', 'B'])
grouped.aggregate(np.sum)
此处的索引就是按照传入参数的顺序来指定的,如果大家习惯用数值编号索引也是可以的,只需要加入as_index参数:
grouped = df.groupby(['A', 'B'], as_index=False)
grouped.aggregate(np.sum)
groupby操作之后仍然可以使用describe()方法来展示所有统计信息
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'])
下面按照索引进行groupby操作:
s = pd.Series(np.random.randn(8), index=index)
grouped = s.groupby(level = 0)
grouped.sum()
grouped = s.groupby(level=1)
grouped.sum()
通过level参数可以指定以哪项为索引进行计算,当level为0时,设置名为first的索引;当level为1时,设置名为second的索引。
grouped = s.groupby(level = 'first')
grouped.sum()
三、常用函数操作
Merge操作
left = pd.DataFrame({'key' : ['K0', 'K1', 'K2', 'K3'],
'A' : ['A0', 'A1', 'A2', 'A3'],
'B' : ['B0', 'B1', 'B2', 'B3']})
right = pd.DataFrame({'key' : ['K0', 'K1', 'K2', 'K3'],
'C' : ['C0', 'C1', 'C2', 'C3'],
'D' : ['D0', 'D1', 'D2', 'D3']})
先创建两个DataFrame,然后用merge将两个DataFrame整合到一起
res = pd.merge(left, right, on = 'key')
这是按照key列把两份数据整合在一起,假如key列不同
left = pd.DataFrame({'key1' : ['K0', 'K1', 'K2', 'K3'],
'key2' : ['K0', 'K1', 'K2', 'K3'],
'A' : ['A0', 'A1', 'A2', 'A3'],
'B' : ['B0', 'B1', 'B2', 'B3']})
right = pd.DataFrame({'key1' : ['K0', 'K1', 'K2', 'K3'],
'key2' : ['K0', 'K1', 'K2', 'K4'],
'C' : ['C0', 'C1', 'C2', 'C3'],
'D' : ['D0', 'D1', 'D2', 'D3']})
res = pd.merge(left, right, on=['key1', 'key2'])
此时如果按照key1和key2整合两份数据,会发现最后一行的数据被抛弃了,如果想考虑所有的结果,还需要额外设置一个how参数:
res = pd.merge(left, right, on=['key1', 'key2'], how='outer')
还可以加入详细的组合说明,指定indicator参数为True即可
res = pd.merge(left, right, on=['key1', 'key2'], how='outer', indicator=True)
也可以单独设置只考虑左边数据或者只考虑右边数据,即以谁为准:
res = pd.merge(left, right, how='left' )
或
res = pd.merge(left, right, how='right' )
缺失值处理
拿到数据之后,经常会遇到数据不干净的现象,即里面可能存在缺失值或者重复片段,这就需要先对数据进行预处理操作。
data = pd.DataFrame({'k1' : ['one']*3+['two']*4,
'k2' : [3, 2, 1, 3, 3, 4, 4]})
此时数据中有几条完全相同的,可以使用drop_duplicates函数去掉多余的数据:
data.drop_duplicates()
也可以只考虑某一列的重复情况,其他全部舍弃:
data.drop_duplicates(subset='k1')
如果要往数据中添加新的列,可以直接指定新的列名或者使用assign函数:
df = pd.DataFrame({'data1' : np.random.randn(5), 'data2' : np.random.randn(5)})
df2 = df.assign(ration = df['data1']/df['data2'])
在数据处理中也经常会遇到缺失值,Pandas中一般用NaN来表示,拿到数据之后,通常都会先看一看缺失情况:
df = pd.DataFrame([range(3), [0, np.nan, 0], [0, 0, np.nan], range(3)])
在创建中加入了两个缺失值,可以直接通过isnull()函数判断所有缺失情况:
df.isnull().any(axis=1)
用fillna函数来填充,在实际处理中通常使用的是均值、中位数等指标。
df.fillna(5)
时间操作
在机器学习中,从始至终都是尽可能多的利用数据所提供的信息,当然时间特征也不例外。当拿到一份时间特征时,最好还是将其转换成标准格式,这样在提取特征时更方便一些:
# 创建一个时间戳
ts = pd.Timestamp('2017-11-24')
s = pd.Series(['2017-11-24 00:00:00', '2017-11-25 00:00:00', '2017-11-26 00:00:00'])
# 将Series转换为标准格式
ts = pd.to_datetime(s)
读取数据时,如果想以时间特征为索引,可以将parse_dates参数设置为True:
data = pd.read_csv('flowdata.csv', index_col=0, parse_dates=True)
有了索引后,就可以用它来取数据了:
data[pd.Timestamp('2012-01-01 09:00'):pd.Timestamp('2012-01-01 19:00')]
# 取2013年的数据
data['2013']
还有个重要的内容:resample重采样:
data.resample('D').mean().head()
原始数据中每天都有好几条数据,但是这里想统计的是每天的平均指标,当然也可以计算其最大值、最小值,只需要把.mean()换成.max()或者.min()即可。
例如想按3天为一个周期进行统计:
data.resample('3D').mean().head()