Python数据分析之Pandas
Python Data Analysis Library 或pandas 是基于NumPy 的一种工具,该工具是为了解决数据分析任务而创建的 Pandas 纳入了大量库和一些标准的数据模型,提供了高效地操作大型数据集所需的工具。pandas 提供了大量能使我们快速便捷地处理数据的函数和方法。
import pandas as pd
import numpy as np
Pandas中有两种常用的基本结构
- Series:一维数组,与Numpy中的一维array类似。二者与Python基本的数据结构List也很相近。Series能保存不同种数据类型,字符串、boolean值、数字等都能保存在Series中。
- DataFrame:二维的表格型数据结构。很多功能与R中的data.frame类似。可以将DataFrame理解为Series的容器。以下的内容主要以DataFrame为主。
Series类型
一维Series可以用一维列表初始化:
s = pd.Series([1,2,3,np.nan])
'''
0 1.0
1 2.0
2 3.0
3 NaN
dtype: float64
'''
s = pd.Series([1,2,3,np.nan],index=['a','b','c','d'])
'''
a 1.0
b 2.0
c 3.0
d NaN
dtype: float64
'''
默认情况下,Series的下标都是数字(可用使用额外参数指定),类型都是统一的。
索引-数据的行标签
print(s.index)
获取值
print(s.values)
print(s['a'])
切片操作(不会改变原数组)
print(s[2:5])
print(s[::2])
索引赋值
s.index.name = "索引"
'''
索引
a 1.0
b 2.0
c 3.0
d NaN
dtype: float64
'''
s.index = list('abcd')
s['a':'d']
DataFrame类型
DataFrame 是一个二维结构,这里首先构造一组时间序列,作为我们第一维的小标
date = pd.date_range('20180101',periods=6)
'''
DatetimeIndex(['2018-01-01', '2018-01-02', '2018-01-03', '2018-01-04',
'2018-01-05', '2018-01-06'],
dtype='datetime64[ns]', freq='D')
'''
创建DataFrame 结构
df = pd.DataFrame(np.random.randn(6,4))
'''
0 1 2 3
0 1.349121 0.429305 1.481158 1.842555
1 -2.082420 -0.993061 0.651757 -0.350710
2 1.137187 1.685110 0.379327 -1.079704
3 0.578643 0.384072 1.297785 -0.465521
4 0.390983 -0.656692 0.762707 -0.281309
5 -0.365502 0.376358 -2.595183 0.634950
'''
df = pd.DataFrame(np.random.randn(6,4),index=date,columns=list('abcd'))
'''
a b c d
2018-01-01 1.751509 0.791480 -0.848589 -1.286318
2018-01-02 0.268522 0.197771 0.241838 -0.649512
2018-01-03 0.897170 -0.639284 0.600405 -0.387560
2018-01-04 -0.161846 -0.592441 0.697815 0.424387
2018-01-05 0.800356 -0.517562 0.145399 0.634336
2018-01-06 -0.281471 0.164059 0.764360 -0.768802
'''
除了向DataFrame中传入二维数组外,我们也可以使用字典传入数据
df2 = pd.DataFrame({'A':1,'B':pd.Timestamp('20180101'),'C':pd.Series(1,index=list(range(4)),dtype=float),'D':np.array([3]*4,dtype=int)})
'''
A B C D
0 1 2018-01-01 1.0 3
1 1 2018-01-01 1.0 3
2 1 2018-01-01 1.0 3
3 1 2018-01-01 1.0 3
'''
df2.dtypes
'''
A int64
B datetime64[ns]
C float64
D int32
dtype: object
'''
字典的每个key代表一列,其value可以是各种能够转化为Series的对象。 与Series要求所有的类型都一致不同,DataFrame只要求每一列数据的格式相同
查看数据
头尾数据 head和tail方法可以分别查看最前面几行和最后面几行的数据(默认为5) :
df.head()
df.head(1)
df.tail()
下标使用index属性查看,列表使用columns属性查看,数据值使用values查看
df.index
df.columns
df.values
pandas读取数据及数据操作
读取excel表格
df = pd.read_excel('paiming.xlsx')
print(df.head(6))
行操作
print(df.iloc[50:53])
dit = {'名字':'hhh'}
s = pd.Series(dit)
s.name = 41452
df = df.append(s)
df= df.drop([name])
列操作
df.columns
df['名字'][1:10]
df['名字','类型']
df['序号'] = range(1,len(df)+1)
df = df.drop['序号',axis=1]
df.loc[[1,2],['名字','类型']]
条件选择
df[df['绩点'] == '3.1490']
df[((df['绩点'] == '3.1490')|(df['绩点'] == '3.3331')))&(df['学号']>3120002520)]
缺失值及异常值处理
缺失值处理方法:
方法 | 说明 |
---|
dropna | 根据标签中的缺失值进行过滤,删除缺失值 | fillna | 对缺失值进行填充 | isnull | 返回一个布尔值对象,判断哪些值是缺失值 | notnull | isnull的否定式 |
df[df['名字'].isnull()]
df['绩点'].fillna(0,inplace=True)
df.dropna()
'''
参数:
- how = 'all' 删除全部为空值的行或列
- inpalce = True 是否覆盖原数据
- axis = 0 选择行或者列
'''
异常值,即在数据集中存在不合理的值,又称离群点。比如年龄为-1,笔记本电脑重量为1吨等,都属于异常值的范围。 对于异常值,一般来说数量都会很少,在不影响整体数据分布的情况下,我们直接删除就可以了。 其他属性的异常值处理,我们会在格式转换部分,进一步讨论。
数据保存
数据处理后,将数据重新保存到movie_data.xlsx
df.to_excel('movie_data.xlsx')
数据格式转换
在做数据分析的时候,原始数据往往会因为各种各样的原因产生各种数据格式的问题。 数据格式是我们非常需要注意的一点,数据格式错误往往会造成很严重的后果。 并且,很多异常值也是我们经过格式转换之后才会发现,对我们规整数据,清洗数据有着重要的作用。
格式
查看格式
df['绩点'].dtype
转换格式
df['绩点']=df['绩点'].astype('int')
排序
默认排序
df[:10]
按某个列排序
df.sort_values(by='列名称',ascending=Flase)[:5]
多个值排序
df.sort_values(by=['第一优先列','第二优先列'])
基本统计分析
描述性统计
dataframe.describe()
'''
排名 学号 高考成绩 ... 2021春季绩点 2021秋季绩点 总计平均分
count 603.000000 6.030000e+02 603.000000 ... 603.000000 603.000000 603.000000
mean 302.000000 3.132757e+09 575.701493 ... 2.694306 2.825201 3.134008
std 174.215384 3.339873e+07 54.071816 ... 0.775117 0.911435 0.605716
min 1.000000 3.118002e+09 0.000000 ... 0.000000 0.000000 0.000000
25% 151.500000 3.120002e+09 578.000000 ... 2.199950 2.310200 2.835641
50% 302.000000 3.120002e+09 579.000000 ... 2.786200 2.966600 3.212758
75% 452.500000 3.120003e+09 581.000000 ... 3.256800 3.489700 3.535538
max 603.000000 3.220003e+09 645.000000 ... 4.443100 4.661500 4.274842
'''
df[df['高考成绩']>580]
df.drop(df[df['高考成绩']>580].index,inplace=True)
df.index=range(len(df))
通过描述性统计,可以发现一些异常值,很多异常值往往是需要我们逐步去发现的。
最值
df['高考成绩'].max()
最小值
df['投票人数'].min()
均值和中值
df['投票人数'].mean()
df['投票人数'].median()
方差和标准差
df['高考成绩'].var()
df['高考成绩'].std()
求和
df['高考成绩'].sum()
相关系数、协方差
df(['平均绩点','高考成绩']).corr()
df(['平均绩点','高考成绩']).cov()
计数(获取唯一值)
len(df)
df['产地'].unique()
我们通常的表格内容中包含了一些重复的数据,比如美国和USA,德国和西德,俄罗斯和苏联。这些数据名称上不同但需要通过数据替换的方法将这些相同合并替换掉
df['产地'].replace('USA','美国',inplace=True)
df['产地'].replace(['西德','苏联'],['德国','俄罗斯'],inplace=True)
计算某列中相同名称的数量的总和
df['产地'].value_counts()
保存数据
df.to_excel()
数据透视
Excel中数据透视表的使用非常广泛,其实Pandas也提供了一个类似的功能,名为pivot_table。 pivot_table非常有用,我们将重点解释pandas中的函数pivot_table。
使用pandas中pivot_table的一个挑战是,你需要确保你理解你的数据,并清楚地知道你想通过透视表解决什么问题。虽然pivot_table看起来只是一个简单的函数,但是它能够快速地对数据进行强大的分析。
基础使用
创建pivot_table
pd.set_option('display.max_columns', 10)
pd.set_option('display.max_rows', 10)
pd.pivot_table(df,index = ['名字'])
'''
总计平均分 排名 高考分数绩点折算 高考成绩
姓名
丁xx 2.474833 538 3.873333 581
万xx 2.956733 415 3.853333 578
于x 3.195592 314 4.086667 571
于x 3.373225 228 4.080000 570
付xx 2.105142 584 4.026667 586
伍xx 3.467825 183 3.880000 582
但xx 3.881017 39 4.046667 610
何xx 1.787017 594 3.866667 580
何xx 3.166258 326 3.873333 581
何xx 3.025292 389 3.866667 580
[10 rows x 12 columns]
Process finished with exit code 0
'''
也可以有多个索引。实际上,大多数的pivot_table参数可以通过列表获取多个值。
pd.pivot_table(df,index=['年代','产地'])
也可以指定需要统计汇总的数据。
pd.pivot_table(df,index=['年代','产地'],values=['评分'])
还可以指定函数,来统计不同的统计值
pd.pivot_table(df,index=["年代","产地"],values=["投票人数","评分"], aggfunc=[np.sum,np.mean])
加入margins=True,可以在下方显示一些总和数据。
pd.pivot_table(df, index=['产地'], aggfunc=[np.sum,np.mean],fill_value=0, margins=True)
对不同值执行不同的函数:可以向aggfunc传递一个字典。不过,这样做有一个副作用,那就是必须将标签做的更加简洁才行。
pd.pivot_table (df, index=['产地'],values=['投票人数','评分'],aggfunc={'投票人数':np. sum,'评分':np.mean}, fill_value=0)
透视表过滤
table-pd.pivot_table(df, index=['年代' ],values=['投票人数' , '评分' ], aggfunc={'投票人数' :np. sum,'评分':np.mean}, fill_value=0)
数据重塑和轴向逆转
层次化索引是pandas的一项主要功能,它能使我们在一个轴上拥有多个索引.
Series的层次化
Series的层次化索引:
s=pd.Series(np.arange(1,10), index=[['a','a','a','b','b','e','e','d','d'],[1,2,3,1,2,3,1,2,3]])
'''
a 1 1
2 2
3 3
b 1 4
2 5
e 3 6
1 7
d 2 8
3 9
dtype: int32
'''
s.index
'''
MultiIndex([('a', 1),
('a', 2),
('a', 3),
('b', 1),
('b', 2),
('e', 3),
('e', 1),
('d', 2),
('d', 3)],
)
'''
可以通过unstack方法可以将Series变成一个DataFrame
s.unstack()
也可以用stack将其转换回Series
s.unstack().stack()
Dataframe的层次化
Dataframe的层次化索引:
data=pd.DataFrame(np.arange(12).reshape(4,3),index=[['a','a','b','b'],[1,2,1,2]],columns=[[' A','A','B'],['Z','X','C'])
data.columns.names = ['col1','col2']
data.rows.names = ['row1','row2']
data.swaplevel('row1','row2')
将列变成索引 和 把索引变成列
df = df.set_index(['产地','年代'])
df.loc['中国']
df = df.reset_index()
让数据的行列进行交换
data.T
dataframe也可以使用stack和unstack,转化为层次化索引的Series
data = data.stack()
data = data.unstack()
数据分组,分组运算
GroupBy技术:实现数据的分组y和分组运算,作用类似于数据透视表
按照电影的产地进行分组:
group = df.groupby(df['产地'])
可以计算分组后的各个统计量
group.mean()
计算每年的平均评分
df['评分'].groupby(df['年代'])
注意groupby 只会对数值变量进行分组运算,所以有值不想参与运算时,可将其转化为字符串
df['年代'] = df['年代'].astype('str')
df.groupby(df['产地']).mean()
print(df.groupby([df['产地'],df['年代']]).mean())
离散化处理
在实际的数据分析项目中,对有的数据属性,我们往往并不关注数据的绝对取值,只关注它所处的区间或者等级。 比如,我们可以把评分9分及以上的电影定义为A,7到9分定义为B,5到7分定义为c,3到5分定义为D,小于3分定义为E。
离散化也可以称为分组、区间化
pd.cut(x,bins,right=True,labels=None,retbins=False,precision=3 ,include_lowest=False)
参数解释:
- ×:需要离散化的数组、Series、DataFrame对象
- bins:分组的依据
- labels:每个分组的说明
例子:
bins = np.percentile(df['投票人数'],[0,20,40,60,80,100])
df['热门程度']=pd.cut(df['投票人数'].bins,labels=['E','D','C','B','A'])
print(df[(df.热门程度=='A')&(df.评分等级=='E')])
合并数据集
df_usa=df[df.产地=='美国']
df_china=df[df.产地=='中国大陆']
pd.merge(left,right,how='inner',on=None,left_on=None,right_on=None,left_index=False,right_index=False,sort=True,suffixes=('_x', '_y'),copy=True,indicator=False)
- left: 拼接的左侧DataFrame对象
- right: 拼接的右侧DataFrame对象
- on: 要加入的列或索引级别名称。 必须在左侧和右侧DataFrame对象中找到。 如果未传递且left_index和right_index为False,则DataFrame中的列的交集将被推断为连接键。
- left_on:左侧DataFrame中的列或索引级别用作键。 可以是列名,索引级名称,也可以是长度等于DataFrame长度的数组。
- right_on: 左侧DataFrame中的列或索引级别用作键。 可以是列名,索引级名称,也可以是长度等于DataFrame长度的数组。
- left_index: 如果为True,则使用左侧DataFrame中的索引(行标签)作为其连接键。 对于具有MultiIndex(分层)的DataFrame,级别数必须与右侧DataFrame中的连接键数相匹配。
- right_index: 与left_index功能相似。
- how: One of ‘left’, ‘right’, ‘outer’, ‘inner’. 默认inner。inner是取交集,outer取并集。比如left:[‘A’,‘B’,‘C’];right[’'A,‘C’,‘D’];inner取交集的话,left中出现的A会和right中出现的买一个A进行匹配拼接,如果没有是B,在right中没有匹配到,则会丢失。'outer’取并集,出现的A会进行一一匹配,没有同时出现的会将缺失的部分添加缺失值。
- sort: 按字典顺序通过连接键对结果DataFrame进行排序。 默认为True,设置为False将在很多情况下显着提高性能。
- suffixes: 用于重叠列的字符串后缀元组。 默认为(‘x’,’ y’)。
- copy: 始终从传递的DataFrame对象复制数据(默认为True),即使不需要重建索引也是如此。
- indicator:将一列添加到名为_merge的输出DataFrame,其中包含有关每行源的信息。 _merge是分类类型,并且对于其合并键仅出现在“左”DataFrame中的观察值,取得值为left_only,对于其合并键仅出现在“右”DataFrame中的观察值为right_only,并且如果在两者中都找到观察点的合并键,则为left_only。
基础实例:
import pandas as pd
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']})
result = pd.merge(left, right, on='key')
result
Out[4]:
A B key C D
0 A0 B0 K0 C0 D0
1 A1 B1 K1 C1 D1
2 A2 B2 K2 C2 D2
3 A3 B3 K3 C3 D3
传入的on的参数是列表:
left = pd.DataFrame({'key1': ['K0', 'K0', 'K1', 'K2'],
'key2': ['K0', 'K1', 'K0', 'K1'],
'A': ['A0', 'A1', 'A2', 'A3'],
'B': ['B0', 'B1', 'B2', 'B3']})
right = pd.DataFrame({'key1': ['K0', 'K1', 'K1', 'K2'],
'key2': ['K0', 'K0', 'K0', 'K0'],
'C': ['C0', 'C1', 'C2', 'C3'],
'D': ['D0', 'D1', 'D2', 'D3']})
result = pd.merge(left, right, on=['key1', 'key2'])
left的keys列表是:[['K0', 'K0'],['K1', 'K0'],['K1', 'K0'],['K2', 'K0']],因此会有1个['K0', 'K0']、2个['K1', 'K0']对应。
result
Out[6]:
A B key1 key2 C D
0 A0 B0 K0 K0 C0 D0
1 A2 B2 K1 K0 C1 D1
2 A2 B2 K1 K0 C2 D2
|