rainzhaojy / blogs

200 stars 28 forks source link

像使用 Excel 一样,用 python 处理分析数据 #13

Closed sushidata closed 6 years ago

sushidata commented 6 years ago

利用 python 进行数据分析

目的:本教程主要是数据分析工作者利用 python 进行数据读取、清理、转换、合并、重塑的方法。

受众:数据分析师 数据产品经理

Author:数据寿司

Email:datasushi@gmail.com

# 加载一些常用的数据分析的包
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
import pandas as pd
df = pd.DataFrame({
    "id":[1001,1002,1003,1004,1005,1006],
    "date":pd.date_range('20130102', periods=6),
    "city":['beijing', 'shanghai', 'guangzhou', 'shenzhen', 'shanghai', 'beijing'],
    "age":[23,44,54,32,34,32],
    "category":['100-A','100-B','110-A','110-C','210-A','130-F'],
    "price":[1200,3299,2133,5433,3299,4432]},
    columns =['id','date','city','category','age','price'])
print df
     id       date       city category  age  price
0  1001 2013-01-02    beijing    100-A   23   1200
1  1002 2013-01-03   shanghai    100-B   44   3299
2  1003 2013-01-04  guangzhou    110-A   54   2133
3  1004 2013-01-05   shenzhen    110-C   32   5433
4  1005 2013-01-06   shanghai    210-A   34   3299
5  1006 2013-01-07    beijing    130-F   32   4432
df1 = pd.DataFrame({
    "id":[1001,1002,1003,1004,1005,1006,1007,1008],
    "gender":['male','female','male','female','male','female','male','female'],
    "pay":['Y','N','Y','Y','N','Y','N','Y',],
    "m-point":[10,12,20,40,40,40,30,20]})
print df1
   gender    id  m-point pay
0    male  1001       10   Y
1  female  1002       12   N
2    male  1003       20   Y
3  female  1004       40   Y
4    male  1005       40   N
5  female  1006       40   Y
6    male  1007       30   N
7  female  1008       20   Y

1、数据的合并 Merge

使用merge函数对两个数据表进行合并,合并的方式为inner,将两个数据表中共有的数据匹配到一起生成新的数据表。并命名为df_inner。

df_inner = pd.merge(df,df1,how='inner')
df_inner
id date city category age price gender m-point pay
0 1001 2013-01-02 beijing 100-A 23 1200 male 10 Y
1 1002 2013-01-03 shanghai 100-B 44 3299 female 12 N
2 1003 2013-01-04 guangzhou 110-A 54 2133 male 20 Y
3 1004 2013-01-05 shenzhen 110-C 32 5433 female 40 Y
4 1005 2013-01-06 shanghai 210-A 34 3299 male 40 N
5 1006 2013-01-07 beijing 130-F 32 4432 female 40 Y

2 、数据的排序 sort_values

df_inner.sort_values(by=['age'])
id date city category age price gender m-point pay
0 1001 2013-01-02 beijing 100-A 23 1200 male 10 Y
3 1004 2013-01-05 shenzhen 110-C 32 5433 female 40 Y
5 1006 2013-01-07 beijing 130-F 32 4432 female 40 Y
4 1005 2013-01-06 shanghai 210-A 34 3299 male 40 N
1 1002 2013-01-03 shanghai 100-B 44 3299 female 12 N
2 1003 2013-01-04 guangzhou 110-A 54 2133 male 20 Y
print df_inner.sort_values(by=['age'])
     id       date       city category  age  price  gender  m-point pay
0  1001 2013-01-02    beijing    100-A   23   1200    male       10   Y
3  1004 2013-01-05   shenzhen    110-C   32   5433  female       40   Y
5  1006 2013-01-07    beijing    130-F   32   4432  female       40   Y
4  1005 2013-01-06   shanghai    210-A   34   3299    male       40   N
1  1002 2013-01-03   shanghai    100-B   44   3299  female       12   N
2  1003 2013-01-04  guangzhou    110-A   54   2133    male       20   Y

3、数据的索引

用来将数据表按索引列的值进行排序

df_inner.sort_index()
id date city category age price gender m-point pay
0 1001 2013-01-02 beijing 100-A 23 1200 male 10 Y
1 1002 2013-01-03 shanghai 100-B 44 3299 female 12 N
2 1003 2013-01-04 guangzhou 110-A 54 2133 male 20 Y
3 1004 2013-01-05 shenzhen 110-C 32 5433 female 40 Y
4 1005 2013-01-06 shanghai 210-A 34 3299 male 40 N
5 1006 2013-01-07 beijing 130-F 32 4432 female 40 Y

4、数据的分组

df_inner['group'] = np.where(df_inner['price'] > 3000,'high','low')
df_inner['group']
0     low
1    high
2     low
3    high
4    high
5    high
Name: group, dtype: object
df_inner
id date city category age price gender m-point pay group
0 1001 2013-01-02 beijing 100-A 23 1200 male 10 Y low
1 1002 2013-01-03 shanghai 100-B 44 3299 female 12 N high
2 1003 2013-01-04 guangzhou 110-A 54 2133 male 20 Y low
3 1004 2013-01-05 shenzhen 110-C 32 5433 female 40 Y high
4 1005 2013-01-06 shanghai 210-A 34 3299 male 40 N high
5 1006 2013-01-07 beijing 130-F 32 4432 female 40 Y high

5、数据分列

对 category 字段的值依次进行分列,并创建数据表,索引值为 df_inner 的索引列,列名称为 category 和size

split = pd.DataFrame((x.split('-') for x in df_inner['category']),index=df_inner.index,columns=['category','size'])
split
category size
0 100 A
1 100 B
2 110 A
3 110 C
4 210 A
5 130 F

这里需要注意的一个用法是 split 函数

str = ('www.google.com')
print str
str_split = str.split('.',1)
print str_split
www.google.com
['www', 'google.com']
#pd.set_option('max_columns',15)
#pd.set_option('display.width',200)
df_inner=pd.merge(df_inner,split,right_index=True, left_index=True)
df_inner
id date city category_x age price gender m-point pay group category_y size
0 1001 2013-01-02 beijing 100-A 23 1200 male 10 Y low 100 A
1 1002 2013-01-03 shanghai 100-B 44 3299 female 12 N high 100 B
2 1003 2013-01-04 guangzhou 110-A 54 2133 male 20 Y low 110 A
3 1004 2013-01-05 shenzhen 110-C 32 5433 female 40 Y high 110 C
4 1005 2013-01-06 shanghai 210-A 34 3299 male 40 N high 210 A
5 1006 2013-01-07 beijing 130-F 32 4432 female 40 Y high 130 F

6、数据提取

第五部分是数据提取,也是数据分析中最常见的一个工作。这部分主要使用三个函数,loc,iloc和ix,loc函数按标签值进行提取,iloc按位置进行提取,ix可以同时按标签和位置进行提取。

按标签提取(loc)

df_inner.loc[3]
id                           1004
date          2013-01-05 00:00:00
city                     shenzhen
category_x                  110-C
age                            32
price                        5433
gender                     female
m-point                        40
pay                             Y
group                        high
category_y                    110
size                            C
Name: 3, dtype: object
df_inner.loc[0:2]
id date city category_x age price gender m-point pay group category_y size
0 1001 2013-01-02 beijing 100-A 23 1200 male 10 Y low 100 A
1 1002 2013-01-03 shanghai 100-B 44 3299 female 12 N high 100 B
2 1003 2013-01-04 guangzhou 110-A 54 2133 male 20 Y low 110 A
df_inner.reset_index()
index id date city category_x age price gender m-point pay group category_y size
0 0 1001 2013-01-02 beijing 100-A 23 1200 male 10 Y low 100 A
1 1 1002 2013-01-03 shanghai 100-B 44 3299 female 12 N high 100 B
2 2 1003 2013-01-04 guangzhou 110-A 54 2133 male 20 Y low 110 A
3 3 1004 2013-01-05 shenzhen 110-C 32 5433 female 40 Y high 110 C
4 4 1005 2013-01-06 shanghai 210-A 34 3299 male 40 N high 210 A
5 5 1006 2013-01-07 beijing 130-F 32 4432 female 40 Y high 130 F
### 下面语句单独执行出错,必须从第一行开始全部运行
df_inner=df_inner.set_index('date')
print df_inner
              id       city category_x  age  price  gender  m-point pay group  \
date                                                                            
2013-01-02  1001    beijing      100-A   23   1200    male       10   Y   low   
2013-01-03  1002   shanghai      100-B   44   3299  female       12   N  high   
2013-01-04  1003  guangzhou      110-A   54   2133    male       20   Y   low   
2013-01-05  1004   shenzhen      110-C   32   5433  female       40   Y  high   
2013-01-06  1005   shanghai      210-A   34   3299    male       40   N  high   
2013-01-07  1006    beijing      130-F   32   4432  female       40   Y  high   

           category_y size  
date                        
2013-01-02        100    A  
2013-01-03        100    B  
2013-01-04        110    A  
2013-01-05        110    C  
2013-01-06        210    A  
2013-01-07        130    F  
df_inner[:'2013-01-04']
id city category_x age price gender m-point pay group category_y size
date
2013-01-02 1001 beijing 100-A 23 1200 male 10 Y low 100 A
2013-01-03 1002 shanghai 100-B 44 3299 female 12 N high 100 B
2013-01-04 1003 guangzhou 110-A 54 2133 male 20 Y low 110 A

按位置提取(iloc)

使用iloc函数按位置对数据表中的数据进行提取,这里冒号前后的数字不再是索引的标签名称,而是数据所在的位置,从0开始。

df_inner.iloc[:3,:2]
id city
date
2013-01-02 1001 beijing
2013-01-03 1002 shanghai
2013-01-04 1003 guangzhou
df_inner.iloc[[0,2,5],[4,5]]
price gender
date
2013-01-02 1200 male
2013-01-04 2133 male
2013-01-07 4432 female

按条件提取(区域和条件值)

除了按标签和位置提起数据以外,还可以按具体的条件进行数据。下面使用loc和isin两个函数配合使用,按指定条件对数据进行提取 。

df_inner['city'].isin(['beijing'])
date
2013-01-02     True
2013-01-03    False
2013-01-04    False
2013-01-05    False
2013-01-06    False
2013-01-07     True
Name: city, dtype: bool
df_inner.loc[df_inner['city'].isin(['beijing','shanghai'])]
id city category_x age price gender m-point pay group category_y size
date
2013-01-02 1001 beijing 100-A 23 1200 male 10 Y low 100 A
2013-01-03 1002 shanghai 100-B 44 3299 female 12 N high 100 B
2013-01-06 1005 shanghai 210-A 34 3299 male 40 N high 210 A
2013-01-07 1006 beijing 130-F 32 4432 female 40 Y high 130 F

数值提取还可以完成类似数据分列的工作,从合并的数值中提取出制定的数值。

category=df_inner['category_x']
pd.DataFrame(category.str[:3])
category_x
date
2013-01-02 100
2013-01-03 100
2013-01-04 110
2013-01-05 110
2013-01-06 210
2013-01-07 130

7、数据筛选

使用与,或,非三个条件配合大于,小于和等于对数据进行筛选,并进行计数和求和。与excel中的筛选功能和countifs和sumifs功能相似。 使用“与”条件进行筛选,条件是年龄大于25岁,并且城市为beijing。筛选后只有一条数据符合要求。

df_inner.loc[(df_inner['age'] > 50)|(df_inner['city'] == 'beijing'), ['id','city','age','category_x','gender']]
id city age category_x gender
date
2013-01-02 1001 beijing 23 100-A male
2013-01-04 1003 guangzhou 54 110-A male
2013-01-07 1006 beijing 32 130-F female
df_inner.loc[(df_inner['age'] > 30)&(df_inner['city'] == 'beijing'), ['id','city','age','category_x','gender']]
id city age category_x gender
date
2013-01-07 1006 beijing 32 130-F female

8、数据筛选

Groupby是进行分类汇总的函数,使用方法很简单,制定要分组的列名称就可以,也可以同时制定多个列名称,groupby按列名称出现的顺序进行分组。同时要制定分组后的汇总方式,常见的是计数和求和两种。

print df_inner
              id       city category_x  age  price  gender  m-point pay group  \
date                                                                            
2013-01-02  1001    beijing      100-A   23   1200    male       10   Y   low   
2013-01-03  1002   shanghai      100-B   44   3299  female       12   N  high   
2013-01-04  1003  guangzhou      110-A   54   2133    male       20   Y   low   
2013-01-05  1004   shenzhen      110-C   32   5433  female       40   Y  high   
2013-01-06  1005   shanghai      210-A   34   3299    male       40   N  high   
2013-01-07  1006    beijing      130-F   32   4432  female       40   Y  high   

           category_y size  
date                        
2013-01-02        100    A  
2013-01-03        100    B  
2013-01-04        110    A  
2013-01-05        110    C  
2013-01-06        210    A  
2013-01-07        130    F  
df_inner.groupby('city').count()
id category_x age price gender m-point pay group category_y size
city
beijing 2 2 2 2 2 2 2 2 2 2
guangzhou 1 1 1 1 1 1 1 1 1 1
shanghai 2 2 2 2 2 2 2 2 2 2
shenzhen 1 1 1 1 1 1 1 1 1 1

可以在groupby中设置列名称来对特定的列进行汇总。下面的代码中按城市对id字段进行汇总计数。

df_inner.groupby('city')['id'].count()
city
beijing      2
guangzhou    1
shanghai     2
shenzhen     1
Name: id, dtype: int64

在前面的基础上增加第二个列名称,分布对city和size两个字段进行计数汇总。

df_inner.groupby(['city','size'])['id'].count()
city       size
beijing    A       1
           F       1
guangzhou  A       1
shanghai   A       1
           B       1
shenzhen   C       1
Name: id, dtype: int64

除了计数和求和外,还可以对汇总后的数据同时按多个维度进行计算,下面的代码中按城市对price字段进行汇总,并分别计算price的数量,总金额和平均金额。

#对city字段进行汇总并计算price的合计和均值。
df_inner.groupby('city')['price'].agg([len,np.sum, np.mean])
len sum mean
city
beijing 2 5632 2816
guangzhou 1 2133 2133
shanghai 2 6598 3299
shenzhen 1 5433 5433

9、数据透视

Excel中的插入目录下提供“数据透视表”功能对数据表按特定维度进行汇总。Python中也提供了数据透视表功能。通过pivot_table函数实现同样的效果。

数据透视表也是常用的一种数据分类汇总方式,并且功能上比groupby要强大一些。下面的代码中设定city为行字段,size为列字段,price为值字段。分别计算price的数量和金额并且按行与列进行汇总。

#数据透视表
pd.pivot_table(df_inner,index=["city"],values=["price"],columns=["size"],aggfunc=[len,np.sum],fill_value=0,margins=True)
len sum
price price
size A B C F All A B C F All
city
beijing 1 0 0 1 2 1200 0 0 4432 5632
guangzhou 1 0 0 0 1 2133 0 0 0 2133
shanghai 1 1 0 0 2 3299 3299 0 0 6598
shenzhen 0 0 1 0 1 0 0 5433 0 5433
All 3 1 1 1 6 6632 3299 5433 4432 19796
#输出到CSV格式
df_inner.to_csv('Excel_to_Python.csv')

10、数据统计

数据采样

Excel的数据分析功能中提供了数据抽样的功能,如下图所示。Python通过sample函数完成数据采样。Sample是进行数据采样的函数,设置n的数量就可以了。函数自动返回参与的结果。

df_inner.sample(n=3)
id city category_x age price gender m-point pay group category_y size
date
2013-01-02 1001 beijing 100-A 23 1200 male 10 Y low 100 A
2013-01-07 1006 beijing 130-F 32 4432 female 40 Y high 130 F
2013-01-03 1002 shanghai 100-B 44 3299 female 12 N high 100 B

Weights参数是采样的权重,通过设置不同的权重可以更改采样的结果,权重高的数据将更有希望被选中。这里手动设置6条数据的权重值。将前面4个设置为0,后面两个分别设置为0.5。

weights = [0, 0, 0, 0, 0.5, 0.5]
df_inner.sample(n=2, weights=weights)
id city category_x age price gender m-point pay group category_y size
date
2013-01-06 1005 shanghai 210-A 34 3299 male 40 N high 210 A
2013-01-07 1006 beijing 130-F 32 4432 female 40 Y high 130 F

描述统计

Describe函数是进行描述统计的函数,自动生成数据的数量,均值,标准差等数据。下面的代码中对数据表进行描述统计,并使用round函数设置结果显示的小数位。并对结果数据进行转置。

df_inner.describe().round(2).T
count mean std min 25% 50% 75% max
id 6 1003.50 1.87 1001 1002.25 1003.5 1004.75 1006
age 6 36.50 10.88 23 32.00 33.0 41.50 54
price 6 3299.33 1523.35 1200 2424.50 3299.0 4148.75 5433
m-point 6 27.00 14.63 10 14.00 30.0 40.00 40
#标准差
df_inner['price'].std()
1523.3516556155596

Cov函数用来计算两个字段间的协方差,可以只对特定字段进行计算,也可以对整个数据表中各个列之间进行计算。

#协方差
#两个字段间的协方差
df_inner['price'].cov(df_inner['m-point'])
17263.200000000001
#数据表中所有字段间的协方差
df_inner.cov()
id age price m-point
id 3.5 -0.7 1946.000000 25.4
age -0.7 118.3 -1354.000000 -31.0
price 1946.0 -1354.0 2320600.266667 17263.2
m-point 25.4 -31.0 17263.200000 214.0

Excel的数据分析功能中提供了相关系数的计算功能,Python中则通过corr函数完成相关分析的操作,并返回相关系数。

Corr函数用来计算数据间的相关系数,可以单独对特定数据进行计算,也可以对整个数据表中各个列进行计算。相关系数在-1到1之间,接近1为正相关,接近-1为负相关,0为不相关。

#相关性分析
df_inner['price'].corr(df_inner['m-point'])
0.77466555617085264
#数据表相关性分析
df_inner.corr()
id age price m-point
id 1.000000 -0.034401 0.682824 0.928096
age -0.034401 1.000000 -0.081720 -0.194833
price 0.682824 -0.081720 1.000000 0.774666
m-point 0.928096 -0.194833 0.774666 1.000000