Pandas数据分析基础

2017年8月29日 - 花瓣数据

一、引入 Pandas

In [1]:
import pandas as pd
import numpy as np

二、Pandas的数据结构

1、Series:一个一维的数组

In [2]:
s1 = pd.Series([1,2,3,4,5],index=['a','b','c','d','e'])
s1
Out[2]:
a    1
b    2
c    3
d    4
e    5
dtype: int64

默认的索引:

In [3]:
s2 = pd.Series([1,2,3,4,5])
s2
Out[3]:
0    1
1    2
2    3
3    4
4    5
dtype: int64

通过索引来访问数据:

In [4]:
s1['c']
Out[4]:
3

直接从Python 字典中创建一个Series:

In [5]:
s3 = pd.Series({'01':'张三','02':'李四','03':'王五'})
s3
Out[5]:
01    张三
02    李四
03    王五
dtype: object

Series索引无值时,自动填充为NaN:

In [6]:
s4 = pd.Series({'01':'张三','02':'李四','03':'王五'},index=['02','01','04','07'])
s4
Out[6]:
02     李四
01     张三
04    NaN
07    NaN
dtype: object

检测缺失值:

In [7]:
pd.isnull(s4)
Out[7]:
02    False
01    False
04     True
07     True
dtype: bool

使用一个标量值初始化Series:

In [8]:
s5 = pd.Series(3.1415,index=['x','y'])
s5
Out[8]:
x    3.1415
y    3.1415
dtype: float64

从NumPy对象中初始化Series:

In [9]:
s6 = pd.Series(np.array([3.14,5.20]),index=['z','y'])
s6
Out[9]:
z    3.14
y    5.20
dtype: float64

在运算的时候自动对齐数据索引:

In [10]:
s5 + s6
Out[10]:
x       NaN
y    8.3415
z       NaN
dtype: float64

2、DataFrame:一组由行和列组成的表格型数据结构

从字典和列表中创建DataFrame:

In [11]:
data = {'年份':[2011,2012,2013,2014,2015],
       '平均年龄':[24.2,25.1,23.5,30.3,28.9],
        '占比':[23,17,20,16,24]
       }
df1 = pd.DataFrame(data)
df1
Out[11]:
占比 平均年龄 年份
0 23 24.2 2011
1 17 25.1 2012
2 20 23.5 2013
3 16 30.3 2014
4 24 28.9 2015

指定列名:

In [12]:
df2 = pd.DataFrame(data,columns=['年份','占比','平均年龄'])
df2
Out[12]:
年份 占比 平均年龄
0 2011 23 24.2
1 2012 17 25.1
2 2013 20 23.5
3 2014 16 30.3
4 2015 24 28.9

查看索引:

In [13]:
df2.index
Out[13]:
RangeIndex(start=0, stop=5, step=1)

修改索引:

In [14]:
df3 = pd.DataFrame(data,columns=['年份','占比','平均年龄'],index=['a','b','c','d','e'])
df3.index
Out[14]:
Index(['a', 'b', 'c', 'd', 'e'], dtype='object')

从相互嵌套的列表中创建DataFrame:

In [15]:
df4 = pd.DataFrame([
['张三', 16, '小学生', '湖南', '男', None],
['李四', 21, '大学生', '湖北', '女', None],
['王五', 22, '大学生', '广东', '男', None],
['赵六', 31, '护士', '广西', '女', None],
['陈七', 28, '律师', '四川', '男', None]],
columns=['姓名', '年龄', '职业', '籍贯', '性别', '奖励'])
df4
Out[15]:
姓名 年龄 职业 籍贯 性别 奖励
0 张三 16 小学生 湖南 None
1 李四 21 大学生 湖北 None
2 王五 22 大学生 广东 None
3 赵六 31 护士 广西 None
4 陈七 28 律师 四川 None

使用类似字典的取值方式,读取DataFrame的列:

In [17]:
df4['姓名']
Out[17]:
0    张三
1    李四
2    王五
3    赵六
4    陈七
Name: 姓名, dtype: object

添加一个新列:

In [18]:
df4['合格'] = None
df4
Out[18]:
姓名 年龄 职业 籍贯 性别 奖励 合格
0 张三 16 小学生 湖南 None None
1 李四 21 大学生 湖北 None None
2 王五 22 大学生 广东 None None
3 赵六 31 护士 广西 None None
4 陈七 28 律师 四川 None None

DataFrame的行能通过指定的位置或名称取出:

In [21]:
df4.iloc[1]
Out[21]:
姓名      李四
年龄      21
职业     大学生
籍贯      湖北
性别       女
奖励    None
合格    None
Name: 1, dtype: object

从文本文件中读取创建DataFrame:

In [ ]:
# 从CSV文件,TXT文件中读取
pd.read_csv()
# 从Excel文件中读取
pd.read_excel()

三、Pandas 必要的基本功能

1、重新索引和修改标签

In [24]:
s2.reindex([0,2,'a',3,'b'])
Out[24]:
0    1.0
2    3.0
a    NaN
3    4.0
b    NaN
dtype: float64

2、头部和尾部

In [25]:
# 生成一个1000个值的随机Serice
s7 = pd.Series(np.random.rand(1000))
In [26]:
# 查看头部,默认5条
s7.head()
Out[26]:
0    0.543632
1    0.027230
2    0.733701
3    0.732225
4    0.173455
dtype: float64
In [27]:
# 查看尾部,默认5条
s7.tail()
Out[27]:
995    0.115653
996    0.685336
997    0.313243
998    0.632566
999    0.521494
dtype: float64

3、二进制运算

In [28]:
df5 = pd.DataFrame(np.arange(9).reshape(3,3),columns=['a','b','c'])
df5
Out[28]:
a b c
0 0 1 2
1 3 4 5
2 6 7 8
In [29]:
df6 = pd.DataFrame(np.arange(8).reshape(2,4),columns=['a','b','c','d'])
df6
Out[29]:
a b c d
0 0 1 2 3
1 4 5 6 7

相加:

In [30]:
df5 + df6
Out[30]:
a b c d
0 0.0 2.0 4.0 NaN
1 7.0 9.0 11.0 NaN
2 NaN NaN NaN NaN
In [31]:
df7 = df5.add(df6, fill_value=0)
df7
Out[31]:
a b c d
0 0.0 2.0 4.0 3.0
1 7.0 9.0 11.0 7.0
2 6.0 7.0 8.0 NaN

是否相等:

In [32]:
df5.eq(df6)
Out[32]:
a b c d
0 True True True False
1 False False False False
2 False False False False

是否不相等:

In [33]:
df5.ne(df6)
Out[33]:
a b c d
0 False False False True
1 True True True True
2 True True True True

是否大于:

In [35]:
df5.gt(df6)
Out[35]:
a b c d
0 False False False False
1 False False False False
2 False False False False

是否小于:

In [36]:
df5.lt(df6)
Out[36]:
a b c d
0 False False False False
1 True True True False
2 False False False False

小于等于:

In [37]:
df5.le(df6)
Out[37]:
a b c d
0 True True True False
1 True True True False
2 False False False False

大于等于:

In [38]:
df5.ge(df6)
Out[38]:
a b c d
0 True True True False
1 False False False False
2 False False False False

4、统计功能

总和:

In [39]:
df5.sum()
Out[39]:
a     9
b    12
c    15
dtype: int64

汇总统计信息:

In [40]:
df5.describe()
Out[40]:
a b c
count 3.0 3.0 3.0
mean 3.0 4.0 5.0
std 3.0 3.0 3.0
min 0.0 1.0 2.0
25% 1.5 2.5 3.5
50% 3.0 4.0 5.0
75% 4.5 5.5 6.5
max 6.0 7.0 8.0

指定汇总统计信息的百分比数据:

In [41]:
df5.describe(percentiles=[0.5, 0.8])
Out[41]:
a b c
count 3.0 3.0 3.0
mean 3.0 4.0 5.0
std 3.0 3.0 3.0
min 0.0 1.0 2.0
50% 3.0 4.0 5.0
80% 4.8 5.8 6.8
max 6.0 7.0 8.0

其他统计函数: value_counts():计算值出现的频率;
count():返回一个非空值在数据对象中数量;
mean(),median(),min(),max():返回平均值、中位值、最小值、最大值;
std(),var(),sem():返回标准差、方差、标准误差;
abs():返回绝对值;

5、函数应用

In [42]:
df5.apply(np.std,axis=1)
Out[42]:
0    0.816497
1    0.816497
2    0.816497
dtype: float64
In [43]:
f = lambda x:x.max() - x.min()
df5.apply(f,axis=1)
Out[43]:
0    2
1    2
2    2
dtype: int64

6、排序

根据行和列来排序:

In [44]:
df7 = pd.DataFrame(np.arange(12).reshape(3,4),
                    columns=['b', 'd', 'a', 'c'],
                    index=['x', 'y', 'z'])
df7
Out[44]:
b d a c
x 0 1 2 3
y 4 5 6 7
z 8 9 10 11
In [45]:
df7.sort_index(axis=1)
Out[45]:
a b c d
x 2 0 3 1
y 6 4 7 5
z 10 8 11 9

根据指定列来排序:

In [46]:
df7.sort_values('b')
Out[46]:
b d a c
x 0 1 2 3
y 4 5 6 7
z 8 9 10 11

7、索引和选择数据

Series中选择按索引选择数据:

In [48]:
s4[['02','07']]
Out[48]:
02     李四
07    NaN
dtype: object

Series中指定索引分配数据:

In [50]:
s4[['02','07']] = '不知道'
s4
Out[50]:
02    不知道
01     张三
04    NaN
07    不知道
dtype: object

DataFrame按列名选择数据:

In [52]:
df5[['a','c']]
Out[52]:
a c
0 0 2
1 3 5
2 6 8

DataFrame按照行和列选择数据:

In [56]:
# 索引一行所有列数据
df5.iloc[0]
Out[56]:
a    0
b    1
c    2
Name: 0, dtype: int32
In [58]:
# 索引一行部分列数据
df5.iloc[0,1:3]
Out[58]:
b    1
c    2
Name: 0, dtype: int32

8、计算工具

相关性计算:

In [59]:
s1 = pd.Series(np.random.rand(3))
s1
Out[59]:
0    0.480759
1    0.765439
2    0.967254
dtype: float64
In [60]:
s2 = pd.Series(np.random.rand(3))
s2
Out[60]:
0    0.467555
1    0.382554
2    0.257695
dtype: float64
In [61]:
s1.cov(s2)
Out[61]:
-0.025248650096077928
In [62]:
df8 = pd.DataFrame(np.random.rand(12).reshape(4,3),columns=['a','b','c'])
df8
Out[62]:
a b c
0 0.959449 0.763208 0.481461
1 0.451402 0.373750 0.204039
2 0.519886 0.287947 0.827656
3 0.593805 0.639148 0.535009
In [63]:
df8.cov()
Out[63]:
a b c
a 0.051288 0.042501 0.003116
b 0.042501 0.049507 -0.010965
c 0.003116 -0.010965 0.065314

协方差计算:

In [64]:
df8.corr(method='spearman')
Out[64]:
a b c
a 1.0 0.8 0.2
b 0.8 1.0 -0.4
c 0.2 -0.4 1.0

不同DataFrame之间的相关性计算:

In [65]:
df9 = pd.DataFrame(np.arange(8).reshape(4,2),columns=['a', 'b'])
df9
Out[65]:
a b
0 0 1
1 2 3
2 4 5
3 6 7
In [66]:
df8.corrwith(df9)
Out[66]:
a   -0.586271
b   -0.265731
c         NaN
dtype: float64

9、处理缺失数据

In [67]:
df10 = df8.reindex(columns=['a','b','c','d'])
df10
Out[67]:
a b c d
0 0.959449 0.763208 0.481461 NaN
1 0.451402 0.373750 0.204039 NaN
2 0.519886 0.287947 0.827656 NaN
3 0.593805 0.639148 0.535009 NaN

发现空值:

In [68]:
df10.isnull()
Out[68]:
a b c d
0 False False False True
1 False False False True
2 False False False True
3 False False False True

删除空值:

In [71]:
df10.dropna(axis=1)
Out[71]:
a b c
0 0.959449 0.763208 0.481461
1 0.451402 0.373750 0.204039
2 0.519886 0.287947 0.827656
3 0.593805 0.639148 0.535009

填充空值:

In [72]:
df10.fillna(888)
Out[72]:
a b c d
0 0.959449 0.763208 0.481461 888.0
1 0.451402 0.373750 0.204039 888.0
2 0.519886 0.287947 0.827656 888.0
3 0.593805 0.639148 0.535009 888.0

四、使用Pandas进行数据分析的高级应用

1、分层索引

In [73]:
s8 = pd.Series(np.random.rand(8), index=[['a','a','b','b','c','c', 'd','d'],[0, 1, 0, 1, 0,1, 0, 1, ]])
s8
Out[73]:
a  0    0.667106
   1    0.849050
b  0    0.334709
   1    0.856721
c  0    0.845210
   1    0.523020
d  0    0.720507
   1    0.194078
dtype: float64

将多层索引的Series规整为一个DataFrame:

In [75]:
s8.unstack()
Out[75]:
0 1
a 0.667106 0.849050
b 0.334709 0.856721
c 0.845210 0.523020
d 0.720507 0.194078

创建一个具有分层索引的DataFrame:

In [76]:
df = pd.DataFrame(np.random.rand(12).reshape(4,3),
                index=[['a', 'a', 'b', 'b'],[0, 1, 0, 1]],
                columns=[['x', 'x', 'y'], [0, 1, 0]])
df
Out[76]:
x y
0 1 0
a 0 0.258729 0.563800 0.113770
1 0.240743 0.078417 0.356486
b 0 0.344421 0.346466 0.212948
1 0.917352 0.782297 0.343008
In [78]:
df.index
Out[78]:
MultiIndex(levels=[['a', 'b'], [0, 1]],
           labels=[[0, 0, 1, 1], [0, 1, 0, 1]])
In [79]:
df.columns
Out[79]:
MultiIndex(levels=[['x', 'y'], [0, 1]],
           labels=[[0, 0, 1], [0, 1, 0]])

分层索引取值:

In [80]:
df['x']
Out[80]:
0 1
a 0 0.258729 0.563800
1 0.240743 0.078417
b 0 0.344421 0.346466
1 0.917352 0.782297
In [84]:
df.iloc[:,0]
Out[84]:
a  0    0.258729
   1    0.240743
b  0    0.344421
   1    0.917352
Name: (x, 0), dtype: float64

在分层索引数据中同样可以使用统计性计算:

In [88]:
df.std(level=0)
Out[88]:
x y
0 1 0
a 0.012718 0.343217 0.171626
b 0.405124 0.308179 0.091966
In [89]:
df.std(level=1)
Out[89]:
x y
0 1 0
0 0.060593 0.153678 0.070129
1 0.478435 0.497718 0.009530