作者:xxw9485
时间:2018/3/10
来源:http://mp.weixin.qq.com/s/pm8503plIouWGAtS3zAM5Q
作为从事数据相关工作的我们,平时接触的更多的是一张有板有眼的数据表格,在这里我们就叫作数据框。在Python中可以通过pandas模块的DataFrame函数构造数据框。
这种创建数据框的方式,默认没有列名称的,不过可以运用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
这种创建数据框的方式,输出结果中列名称顺序与构造时的数据不一致,这是因为字典并非是一种序列,而是一种特殊的键值对关系的对象。如果你需要按照指定的列顺序排列,仍然可以通过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
在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则是设置读取原始数据的哪些列。
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-2000人
2 上海 上海晶樵网络信息技术有限公司 57561 SPD 50-150人
3 上海 杭州数云信息技术有限公司上海分公司 7502 数云 150-500人
4 上海 上海银基富力信息技术有限公司 130876 银基富力 15-50人
使用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()
在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 上海 纽海信息技术(上海)有限公司
有时,在一张表里你可能需要删除与建模或分析无关紧要的变量,如用户id、姓名、邮编号码等。在Python中,你可以借助于drop函数非常轻松的删除指定的变量。
# 输入:
print(a.drop(['number'], axis = 1).head(1))
# 输出:
city company name people
0 上海 纽海信息技术(上海)有限公司 1号店 2000人以上
注意:该函数默认的axis=0,表示删除行观测,如果需要删除列,就要将axis设置为1。记住,此时虽然删除了两个变量,但数据集本身是没有变化的,如果你需要改变数据集,需要设置inplace为True。
需要更换变量名时,rename函数可以帮助我们解决问题:
# 输入:
print(a.rename(columns={'city':'城市'}).head(1))
# 输出:
城市 company number name people
0 上海 纽海信息技术(上海)有限公司 8581 1号店 2000人以上
字符型数值转数值:可以通过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
如果你需要对你的数据集进行排序,Python中pandas模块也提供了非常好用的sort_values函数。
# 输入:
print(a.sort_values(by = ['number'],ascending = [True]).head())
# 输出:
city company number name people
6 上海 上海好体信息科技有限公司 2002 足球魔方 150-500人
3 上海 杭州数云信息技术有限公司上海分公司 7502 数云 150-500人
0 上海 纽海信息技术(上海)有限公司 8581 1号店 2000人以上
7 上海 上海安硕信息技术股份有限公司 21863 安硕信息(amarsoft) 2000人以上
1 上海 上海点荣金融信息服务有限责任公司 23177 点融网 500-2000人
在数据清洗中,往往都要检查一下数据集的观测行是否有重复,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
pandas模块有一个sample函数可以帮助我们完成抽样的任务,语法:
sample(n = None, frac = None, replace = False, weights = None, random_state = None)
# 输入:
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-150人
9 上海 五五海淘(上海)科技股份有限公司 58109 55海淘 150-500人
6 上海 上海好体信息科技有限公司 2002 足球魔方 150-500人
4 上海 上海银基富力信息技术有限公司 130876 银基富力 15-50人
0 上海 纽海信息技术(上海)有限公司 8581 1号店 2000人以上
city company number name people
1 上海 上海点荣金融信息服务有限责任公司 23177 点融网 500-2000人
3 上海 杭州数云信息技术有限公司上海分公司 7502 数云 150-500人
5 上海 上海青之桐投资管理有限公司 28095 青桐资本 50-150人
7 上海 上海安硕信息技术股份有限公司 21863 安硕信息(amarsoft) 2000人以上
8 上海 上海崇杏健康管理咨询有限公司 121208 上海崇杏 15-50人
训练集可以直接从sample函数中抽取出来,测试集则通过索引的方式,将训练集中的行号排除出去。
频数统计,顾名思义就是统计某个离散变量各水平的频次。
# 输入:
print(a.people.value_counts(),'\n') # 统计各个people小组的人数
print(a.people.value_counts()/sum(a.people.value_counts())) # 统计各个people小组的占比情况
# 输出:
150-500人 3
2000人以上 2
50-150人 2
15-50人 2
500-2000人 1
Name: people, dtype: int64
150-500人 0.3
50-150人 0.2
15-50人 0.2
2000人以上 0.2
500-2000人 0.1
Name: people, dtype: float64
需要统计两个离散变量的交叉统计表时,可以使用pandas模块提供的crosstab函数。
# 输入:
b = pd.crosstab(index = a.city, columns = a['people'])
print(b)
# 输出:
people 15-50人 150-500人 2000人以上 50-150人 500-2000人
city
上海 2 3 2 2 1
对于缺失值我们可以通过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
# 输入:
# 整个数据集是否存在缺失
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
映射函数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
如果你想要做类似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
如果你手中有多张数据结构一致的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初始化为列表结构。
如果你所需的数据集来自于多张表,而这些表之间存在一些公共的字段用于观测行的匹配,换句话说,你需要在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)
# 有公共字段且字段名称一样的两个数据集的连接
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()
在建模过程中,往往会有一些离散变量,如学历、收入等级,用户会员等级。这些变量直接放入到模型中(如回归模型)是有问题的(即使你已经用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)为参照组。
把连续变量进行分段处理,如年龄需要分成未成年、青年、中年和老年;收入需要分成低收入群体、中等收入群体和高收入群体,这时可以用到pandas.cut()函数。
语法:
pandas.cut(x, bins, right=True, labels=None, retbins=False, precision=3,include_lowest=False)
# 输入:
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): [未成年 < 青年 < 中年 < 老年]