Python3基本工具包:Pandas(2)

作者:xxw9485
时间:2018/3/10
来源:http://mp.weixin.qq.com/s/pm8503plIouWGAtS3zAM5Q


2、数据框

作为从事数据相关工作的我们,平时接触的更多的是一张有板有眼的数据表格,在这里我们就叫作数据框。在Python中可以通过pandas模块的DataFrame函数构造数据框。

2.1 数据框的构造

2.1.1 通过列表创建数据框

这种创建数据框的方式,默认没有列名称的,不过可以运用DataFrame函数中的columns参数给数据框的每列添加名称。如果你需要给行加上索引名称,你可以使用index参数。

# 输入:
# 构造数据框
import pandas as pd
a = pd.DataFrame([[1,2,3],[10,20,30],[100,200,300],[1,10,100]])
print(a,'\n')
b = pd.DataFrame([[1,2,3],[10,20,30],[100,200,300],[1,10,100]],columns=['v1','v2','v3']) # 添加列名称
print(b)
# 输出:
     0    1    2
0    1    2    3
1   10   20   30
2  100  200  300
3    1   10  100

    v1   v2   v3
0    1    2    3
1   10   20   30
2  100  200  300
3    1   10  100

2.1.2 通过字典创建数据框

这种创建数据框的方式,输出结果中列名称顺序与构造时的数据不一致,这是因为字典并非是一种序列,而是一种特殊的键值对关系的对象。如果你需要按照指定的列顺序排列,仍然可以通过columns参数实现。

# 输入:
import pandas as pd
a = pd.DataFrame({'id':[1,2,3],'name':['Tom','Lily','Jim'],'age':[20,21,22]})
print(a,'\n')
b = pd.DataFrame({'id':[1,2,3],'name':['Tom','Lily','Jim'],'age':[20,21,22]},columns=['id','name','age'])
print(b)
# 输出:
   age  id  name
0   20   1   Tom
1   21   2  Lily
2   22   3   Jim 

   id  name  age
0   1   Tom   20
1   2  Lily   21
2   3   Jim   22

2.2 数据的读入

2.2.1 文本文件的读取

在pandas模块中有read_table和read_csv两个函数读取常见的文本文件。read_table和read_csv两个函数都可以读文本文件数据,区别在于默认的sep参数不一致,read_table默认以制表符Tab键为字段间的间隔符,而read_csv默认以逗号为字段间的间隔符。

# 输入:
import pandas as pd
books = pd.read_table('book.csv',sep=',',header=None,usecols=[0,1,3],names=['type','title','author'])
print(books.tail(),'\n') # 默认输出最后5行
print(books.tail(1),'\n') # 输出最后1行
print(books.head(),'\n') # 默认输出前5行
print(books.head(1)) # 输出前1行
# 输出:
   type     title author
5  spss  spss2015     小明
6  spss  spss2016     小明
7  spss  spss2017     小明
8  spss  spss2018     小明
9  spss  spss2019     小明 

   type     title author
9  spss  spss2019     小明

   type     title author
0  spss  spss2010     小明
1  spss  spss2011     小明
2  spss  spss2012     小明
3  spss  spss2013     小明
4  spss  spss2014     小明 

   type     title author
0  spss  spss2010     小明

由于原始数据文件books.txt没有字段名称,故设置header=None,并用names参数给表字段加上名称,usecols则是设置读取原始数据的哪些列。

2.2.2 电子表格的读取

pandas模块中read_excel函数可以非常方便的读取外部的xls和xlsx电子表格:

# 输入:
import pandas as pd
a = pd.read_excel(r'D:\Python36\test2018.3.19\test.xlsx',header=None)
print(a.head()) # 数据集的前五行
# 输出:
    0                  1       2     3          4
0  上海     纽海信息技术(上海)有限公司    8581   1号店    2000人以上
1  上海   上海点荣金融信息服务有限责任公司   23177   点融网  500-20002  上海     上海晶樵网络信息技术有限公司   57561   SPD    50-1503  上海  杭州数云信息技术有限公司上海分公司    7502    数云   150-5004  上海     上海银基富力信息技术有限公司  130876  银基富力     15-50

2.2.3 MySQL数据库数据的读取

使用Python读取MySQL数据库,还需要结合pymysql模块一起使用。
在MySQL中创建数据:

# 建库
create database test;
# 调用库名称
use test;
# 创建表
create table user_info(
id int,
name varchar(10),
gender varchar(2),
age tinyint,
income smallint);
# 赋值
insert into user_info values
(1,'Tom','M',28,15000),
(2,'Lily','F',27,17000),
(3,'Lucy','F',37,15600),
(4,'Jim','M',29,20000),
运用Python与MySQL创建连接,并读取数据:
import pymysql 
import pandas as pd
# 创建连接
conn = pymysql.connect(host='localhost',port=3306,user='root',password='123456',database='test',charset='utf8')
user_info = pd.read_sql('select * from user_info',conn) # 读取数据
print(user_info)
# 关闭连接
conn.close() 

2.3 数据的概览信息

  • shape属性和columns属性返回数据集的行列数及变量名;
  • describe属性可以对数值型变量(include=[‘number’])和离散型变量(include=[‘object’])进行描述性统计;
  • info属性则对数据集的变量类型进行简单的描述。

2.4 数据筛选

在pandas取出一列有两种方法,一种是比较普遍适用的名称索引法,另一种则是点取法。

# 输入:
import pandas as pd
a = pd.read_excel(r'D:\Python36\test2018.3.19\test.xlsx')
print(a.head(1),'\n') # 数据集的前1行
print(a['city'].head()) #名称索引法取出某列数据
#print(a.city.head()) #点取法取出某列数据,结果同上
# 输出:
  city            company  number  name     people
0   上海     纽海信息技术(上海)有限公司    8581   1号店    2000人以上

0    上海
1    上海
2    上海
3    上海
4    上海
Name: city, dtype: object

如果使用点取法取出数据集中的某列,需要注意的是列的名称必须是一个整体,例如stu age或stu.age等格式的变量名就不能使用点取法。
如果你需要取出多列数据时,那不管是Python还是R语言只能使用名称索引或位置索引了。

  • 一个变量的观测筛选:
# 输入:
print(a.loc[a.people=='2000人以上',:].head())
# 输出:
  city         company  number            name   people
0   上海  纽海信息技术(上海)有限公司    8581             1号店  2000人以上
7   上海  上海安硕信息技术股份有限公司   21863  安硕信息(amarsoft)  2000人以上
  • 两个变量的观测筛选:
# 输入:
print(a.loc[(a.people=='2000人以上')&(a.name=='1号店'),:])
# 输出:
  city         company  number name   people
0   上海  纽海信息技术(上海)有限公司    8581  1号店  2000人以上

需要注意的是:多个变量的筛选,可以是或(|)关系、可以是且(&)关系还可以是非(~)关系,一定要用圆括号把条件括起来。

  • 两个变量的观测筛选并筛选部分变量:
# 输入:
print(a.loc[(a.people=='2000人以上')&(a.name=='1号店'),['city','company']])
# 输出:
  city         company
0   上海  纽海信息技术(上海)有限公司

2.5 变量的删除

有时,在一张表里你可能需要删除与建模或分析无关紧要的变量,如用户id、姓名、邮编号码等。在Python中,你可以借助于drop函数非常轻松的删除指定的变量。

# 输入:
print(a.drop(['number'], axis = 1).head(1))
# 输出:
  city            company  name     people
0   上海     纽海信息技术(上海)有限公司   1号店    2000人以上

注意:该函数默认的axis=0,表示删除行观测,如果需要删除列,就要将axis设置为1。记住,此时虽然删除了两个变量,但数据集本身是没有变化的,如果你需要改变数据集,需要设置inplace为True。

2.6 变量重命名

需要更换变量名时,rename函数可以帮助我们解决问题:

# 输入:
print(a.rename(columns={'city':'城市'}).head(1))
# 输出:
   城市         company  number name   people
0  上海  纽海信息技术(上海)有限公司    8581  1号店  2000人以上

2.7 数据类型转化

字符型数值转数值:可以通过astype函数把字符型变量转化为整数型和浮点型。
实例:

# 输入
print(a.dtypes)
a = a.astype({'number':'object'})
print(a.dtypes)
# 输出
city       object
company    object
number      int64
name       object
people     object
dtype: object
city       object
company    object
number     object
name       object
people     object
dtype: object

2.8 数据集的排序

如果你需要对你的数据集进行排序,Python中pandas模块也提供了非常好用的sort_values函数。

# 输入:
print(a.sort_values(by = ['number'],ascending = [True]).head())
# 输出:
  city            company  number            name     people
6   上海       上海好体信息科技有限公司    2002            足球魔方   150-5003   上海  杭州数云信息技术有限公司上海分公司    7502              数云   150-5000   上海     纽海信息技术(上海)有限公司    8581             1号店    2000人以上
7   上海     上海安硕信息技术股份有限公司   21863  安硕信息(amarsoft)    2000人以上
1   上海   上海点荣金融信息服务有限责任公司   23177             点融网  500-2000

2.9 数据去重

在数据清洗中,往往都要检查一下数据集的观测行是否有重复,duplicated函数可以用来检查数据集是否重复,如果重复,则会在重复的行显示True。然后,通过drop_duplicates函数对数据集的重复观测进行删除。这两个函数均有subset参数,默认对数据集的所有变量进行重复性检测和删除,如果你需要指定某些变量的重复性检查和删除就可以往subset参数传递变量。

# 输入:
import pandas as pd
data = pd.DataFrame({'name':['liu','li','chen','liu'],
                    'age':[20,21,22,20],
                    'gender':['M','M','M','M']})
print(data)
print(data.duplicated()) # 检查数据集是否重复
print(data.drop_duplicates()) # 删除重复观测
print(data.duplicated(subset='gender')) # 指定检测某个变量是否重复
# 输出:
   age gender  name
0   20      M   liu
1   21      M    li
2   22      M  chen
3   20      M   liu
0    False
1    False
2    False
3     True
dtype: bool
   age gender  name
0   20      M   liu
1   21      M    li
2   22      M  chen
0    False
1     True
2     True
3     True
dtype: bool

2.10 数据抽样

pandas模块有一个sample函数可以帮助我们完成抽样的任务,语法:

sample(n = None, frac = None, replace = False, weights = None, random_state = None)
  • n:指定抽样的个数
  • frac:指定抽样的比例
  • replace:指定是否有放回的抽样,默认为无放回抽样
  • weights:指定每个样本被抽中的概率,默认每个样本抽中的概率相等
  • random_state :指定抽样的随机种子,默认无固定的随机种子,即每次抽样的结果不一样
# 输入:
import pandas as pd
a = pd.read_excel(r'D:\Python36\test2018.3.19\test.xlsx')
train = a.sample(frac = 0.5, random_state = 1)
print(train,'\n')
test = a.loc[~a.index.isin(train.index),:] # "~"表示非
print(test)
# 输出:
  city           company  number  name    people
2   上海    上海晶樵网络信息技术有限公司   57561   SPD   50-1509   上海  五五海淘(上海)科技股份有限公司   58109  55海淘  150-5006   上海      上海好体信息科技有限公司    2002  足球魔方  150-5004   上海    上海银基富力信息技术有限公司  130876  银基富力    15-500   上海    纽海信息技术(上海)有限公司    8581   1号店   2000人以上 

  city            company  number            name     people
1   上海   上海点荣金融信息服务有限责任公司   23177             点融网  500-20003   上海  杭州数云信息技术有限公司上海分公司    7502              数云   150-5005   上海      上海青之桐投资管理有限公司   28095            青桐资本    50-1507   上海     上海安硕信息技术股份有限公司   21863  安硕信息(amarsoft)    2000人以上
8   上海     上海崇杏健康管理咨询有限公司  121208            上海崇杏     15-50

训练集可以直接从sample函数中抽取出来,测试集则通过索引的方式,将训练集中的行号排除出去。

2.11 频数统计

频数统计,顾名思义就是统计某个离散变量各水平的频次。

# 输入:
print(a.people.value_counts(),'\n') # 统计各个people小组的人数
print(a.people.value_counts()/sum(a.people.value_counts())) # 统计各个people小组的占比情况
# 输出:
150-5003
2000人以上      2
50-1502
15-502
500-20001
Name: people, dtype: int64

150-5000.3
50-1500.2
15-500.2
2000人以上      0.2
500-20000.1
Name: people, dtype: float64

需要统计两个离散变量的交叉统计表时,可以使用pandas模块提供的crosstab函数。

# 输入:
b = pd.crosstab(index = a.city, columns = a['people'])
print(b)
# 输出:
people  15-50150-5002000人以上  50-150500-2000人
city                                                 
上海           2         3        2        2          1

2.12 缺失值处理

对于缺失值我们可以通过pandas模块中的isnull函数监控每个变量是否存在缺失,缺失的比例如何,然后通过pandas模块中的dropna函数和fillna函数进行删除或替补处理。

  • 首先,我们手工编造一个含缺失值的数据框:
# 输入:
import pandas as pd
import numpy as np
df = pd.DataFrame([[1,2,3,4],[np.NaN,6,7,np.NaN],[11,np.NaN,12,13],
                 [100,200,300,400],[20,40,60,np.NaN]], columns = ['x1','x2','x3','x4'])
print(df)
# 输出:
      x1     x2   x3     x4
0    1.0    2.0    3    4.0
1    NaN    6.0    7    NaN
2   11.0    NaN   12   13.0
3  100.0  200.0  300  400.0
4   20.0   40.0   60    NaN
  • 其次,使用isnull函数检查数据集的缺失情况:
# 输入:
# 整个数据集是否存在缺失
print(any(df.isnull()),'\n') 
# 每一列是否有缺失、以及缺失比例
is_null = []
null_ratio = []
for col in df.columns:
    is_null.append(any(pd.isnull(df[col])))
    null_ratio.append(float(round(sum(pd.isnull(df[col]))/df.shape[0],2)))
print(is_null,'\n', null_ratio, '\n')
# 每一行是否有缺失
is_null = []
for index in list(df.index):
    is_null.append(any(pd.isnull(df.iloc[index,:])))
print(is_null,'\n')
# 输出:
True 

[True, True, False, True] 
 [0.2, 0.2, 0.0, 0.4] 

[False, True, True, False, True] 
  • 最后,对缺失数据进行处理:
删除法

dropna函数,有两种删除模式,一种是对含有缺失的行(任意一列)进行删除,另一种是删除那些全是缺失(所有列)的行:

# 输入:
print(df.dropna(),'\n') # 删除任何含有缺失的行
print(df.dropna(how = 'all')) # 删除全是缺失的行
# 输出:
      x1     x2   x3     x4
0    1.0    2.0    3    4.0
3  100.0  200.0  300  400.0 

      x1     x2   x3     x4
0    1.0    2.0    3    4.0
1    NaN    6.0    7    NaN
2   11.0    NaN   12   13.0
3  100.0  200.0  300  400.0
4   20.0   40.0   60    NaN
替补法

fillna函数提供前向替补、后向替补和函数替补的几种方法:

# 输入:
print(df.fillna(method='ffill'),'\n') # 前向替补
print(df.fillna(method='bfill'),'\n') # 后向替补
# 不同的列用不同的函数替补
print(df.fillna(value = {'x1':df.x1.mean(),
                        'x2':df.x2.median(),
                        'x4':df.x4.max()}))
# 输出:
      x1     x2   x3     x4
0    1.0    2.0    3    4.0
1    1.0    6.0    7    4.0
2   11.0    6.0   12   13.0
3  100.0  200.0  300  400.0
4   20.0   40.0   60  400.0 

      x1     x2   x3     x4
0    1.0    2.0    3    4.0
1   11.0    6.0    7   13.0
2   11.0  200.0   12   13.0
3  100.0  200.0  300  400.0
4   20.0   40.0   60    NaN 

      x1     x2   x3     x4
0    1.0    2.0    3    4.0
1   33.0    6.0    7  400.0
2   11.0   23.0   12   13.0
3  100.0  200.0  300  400.0
4   20.0   40.0   60  400.0

2.13 数据映射

映射函数apply的目的就是将用户指定的函数运用到数据集的纵轴(即各个变量)或横轴(即各个行)。实例:

# 输入:
# 查看各列和各行是否有缺失
# 创建一个判断对象是否含缺失的匿名函数
import pandas as pd
import numpy as np
df = pd.DataFrame([[1,2,3,4],[np.NaN,6,7,np.NaN],[11,np.NaN,12,13],
                 [100,200,300,400],[20,40,60,np.NaN]], columns = ['x1','x2','x3','x4'])
isnull = lambda x : any(pd.isnull(x))
print(df.apply(func = isnull, axis = 0),'\n') # axis=0表示将isnull函数映射到各列
print(df.apply(func = isnull, axis = 1)) # axis=1表示将isnull函数映射到各行
# 输出:
x1     True
x2     True
x3    False
x4     True
dtype: bool 

0    False
1     True
2     True
3    False
4     True
dtype: bool

需要计算每个学生的总成绩,或各科的平均分,也可以用apply函数实现。实例:

# 输入:
import pandas as pd
import numpy as np
df = pd.DataFrame([['a',99,88,77],['b',98,87,76],['c',100,90,80],
                 ['d',95,80,85],['e',90,89,99]], columns = ['name','chinese','math','english'])
print(df)
df['total'] = df.iloc[:,1:5].apply(func = np.sum, axis = 1) # 每个学生的总成绩
print(df)
avg = df.iloc[:,1:5].apply(func = np.mean, axis = 0) # 每门学科的平均成绩
print(avg)
# 输出:
  name  chinese  math  english
0    a       99    88       77
1    b       98    87       76
2    c      100    90       80
3    d       95    80       85
4    e       90    89       99
  name  chinese  math  english  total
0    a       99    88       77    264
1    b       98    87       76    261
2    c      100    90       80    270
3    d       95    80       85    260
4    e       90    89       99    278
chinese     96.4
math        86.8
english     83.4
total      266.6
dtype: float64

2.14 数据汇总

如果你想要做类似SQL中的聚合操作,pandas也提供了实现该功能的函数,即groupby函数与aggregate函数的搭配使用。

# 输入
import pandas as pd
import numpy as np
df = pd.DataFrame([['a','f',99,88,77],['b','m',98,87,76],['c','m',100,90,80],
                 ['d','f',95,80,85],['e','m',90,89,99]], columns = ['name','sex','chinese','math','english'])
# 对性别gender做分组统计各数值型变量的平均值
groupby_gender = df.groupby(['sex'])
b = groupby_gender.aggregate(np.mean)
print(b)
# 对性别gender和班级class两个变量做分组统计各数值型变量的平均值
grouped = df.groupby(['sex','name'])
c = grouped.aggregate(np.mean)
print(c)
# 对chinese算平均值,对math算中位数
d = grouped.aggregate({'chinese':np.mean,'math':np.median}) 
print(d)
# 输出
     chinese       math  english
sex                             
f       97.0  84.000000     81.0
m       96.0  88.666667     85.0
          chinese  math  english
sex name                        
f   a          99    88       77
    d          95    80       85
m   b          98    87       76
    c         100    90       80
    e          90    89       99
          chinese  math
sex name               
f   a          99    88
    d          95    80
m   b          98    87
    c         100    90
    e          90    89

2.15 数据集的纵向合并

如果你手中有多张数据结构一致的excel表格,你需要将这些表格合并到一起,你会怎么做?复制粘贴?是不是太慢了,这里教你使用Python完成数据的批量合并。
实例:

import os
import pandas as pd
# 指定数据文件所在的路径
path = 'D:\\data file\\data1\\'
# 罗列路径下的文件名称
filenames = os.listdir(path)
# 通过for循环完成数据的堆叠
dataframes = []
for file in filenames:
    dataframes.append(pd.read_excle(path  + file))
alldata = pd.concat(dataframes, ignore_index=True)
alldata.head()

注意:pd.concat函数的第一个参数一定要是一个可迭代对象。故在代码中对dataframe初始化为列表结构。

2.16 数据集的横向扩展

如果你所需的数据集来自于多张表,而这些表之间存在一些公共的字段用于观测行的匹配,换句话说,你需要在excel使用vlookup这样的函数完成数据的连接。借助于pandas中merge函数完成两个数据集的连接。如果你的两张表有公共字段,而且字段名称完全一致,merge函数会自动查询这些字段,并以这些字段作为连接的依据。如果两张表中含公共字段,但名称不一致,如Id与id,这个时候就需要left_on和right_on两个参数的使用了。
语法:

pd.merge(left, right, how='inner', on=None, left_on=None, right_on=None,
        left_index=False, right_index=False,sort=False,
        suffixes=('_x','_y'), copy=True, indicator=False)
  • left,right:为需要连接的两张表;
  • how:默认对两张表进行内连,‘right’,‘left’为右连和左连;
  • on:指定关联两张表的公共字段;
  • left_on,right_on:指定left表和right表中需要关联的字段;
  • left_index,right_index:指定left表和right表中需要关联的行索引
    实例:
# 有公共字段且字段名称一样的两个数据集的连接
merge_data = pd.merge(user_info, economy_info, how = 'left') 
merge_data.head()
# 有公共字段且字段名称不一样的两个数据集的连接
merge_data2 = pd.merge(user_info, economy_info, how = 'left', left_on = 'ID', right_on = 'id')
merge_data2.head()

2.17 离散变量的哑变量处理

在建模过程中,往往会有一些离散变量,如学历、收入等级,用户会员等级。这些变量直接放入到模型中(如回归模型)是有问题的(即使你已经用1,2,3…等数据表示),为解决这个问题,我们通常是将这些变量进行哑变量处理。如果离散变量有N种水平,就需要构造N-1个变量,每一个变量均用0和1的值来表示。这时需要用到pandas模块中的get_dummies函数。
实例:

# 输入:
import pandas as pd
import numpy as np
a = pd.DataFrame([['a','f',99,88,77],['b','m',98,87,76],['c','m',100,90,80],
                 ['d','f',95,80,85],['e','m',90,89,99]], columns = ['name','sex','chinese','math','english'])
print(a)
b = pd.get_dummies(a, columns = ['sex']).head() # 哑变量处理
print(b)
c = b.drop(['sex_f'], axis = 1).head() # 删除字段sex_f
print(c)
# 输出:
  name sex  chinese  math  english
0    a   f       99    88       77
1    b   m       98    87       76
2    c   m      100    90       80
3    d   f       95    80       85
4    e   m       90    89       99
  name  chinese  math  english  sex_f  sex_m
0    a       99    88       77      1      0
1    b       98    87       76      0      1
2    c      100    90       80      0      1
3    d       95    80       85      1      0
4    e       90    89       99      0      1
  name  chinese  math  english  sex_m
0    a       99    88       77      0
1    b       98    87       76      1
2    c      100    90       80      1
3    d       95    80       85      0
4    e       90    89       99      1

千万记得,如果你的变量进行了哑变量处理,建模时要记得删除原离散变量中的某一个水平,如性别中删除sex_f。删除的变量,就表示性别中,以女性(f)为参照组。

2.18 连续变量的分段

把连续变量进行分段处理,如年龄需要分成未成年、青年、中年和老年;收入需要分成低收入群体、中等收入群体和高收入群体,这时可以用到pandas.cut()函数。
语法:

pandas.cut(x, bins, right=True, labels=None, retbins=False, precision=3,include_lowest=False)
  • x:表示需要切割处理的变量;
  • bins:表示切割后的边界值,即分组情况;
  • right:等于False时表示分段的数据区间不包含上限;
  • labels:对应bins切割区间的标签
    实例:
# 输入:
import numpy as np
import pandas as pd
np.random.seed(1)
age = np.random.randint(low = 12, high = 80, size =1000) # 随机生成一个年龄的字段
age = pd.Series(age) # 化为序列
print(age.head(),'\n')
age_cut = pd.cut(age, bins = [0,18,45,60,80], right = False, labels = ['未成年','青年','中年','老年'])
print(age_cut.head()) # 把年龄序列切割为四个区间,18岁以下为未成年;18~45岁为青年;45~60岁为中年;60岁以上为老年
# 输出:
0    49
1    24
2    21
3    17
4    76
dtype: int32 

0     中年
1     青年
2     青年
3    未成年
4     老年
dtype: category
Categories (4, object): [未成年 < 青年 < 中年 < 老年]

你可能感兴趣的:(数据处理,Python学习笔记)