python pandas模块_Python模块-pandas

数据分析虽说很多时候需要对业务和数据的理解,但其实大部分时候对数据的操作是相似(即使使用不同的工具,如Excel、Python、R等),像是数据清洗、表格结构修改、字段切分、分组计算等等。下面是使用Python中的Pandas包对数据分析常用操作的笔记。

数据读取

pandas读取文件后的数据集是一个DataFrame对象,该对象的每个列是一个Series对象

# pandas可读取很多文件格式

# 但一般读取数据的文件格式为:csv 和 excel

import pandas as pd

df = pd.read_csv("iris.csv",

sep=',',

names=["A","B","C","D"],

nrows=2, # 只要前两行的数据

encoding='utf-8'

)

df = pd.read_excel("iris.xlsx",

sheetname='XXXX',

header=0, # 指定第一行为表头

index_col=0, # 指定第一列为索引

usecols = [0, 2] # 只要第一和三列的数据

)

# 数据库读取

import pymysql # MySQL

import pymssql # SQLserver

conn = pymssql.connect(host='XXX.XX.XX.XX', user='username', password='123', database='DB')

OS = pd.read_sql("SELECT * FROM [KF_SZ].[dbo].[OSdepartrelation]",conn)

conn.close()

数据探索

# 查看数据量和特征量

df.shape

>>> (68630, 14)

# 查看数据集的头5行

df.head()

# 查看数据集的尾5行

df.tail()

# 查看行名

df.index

>>> RangeIndex(start=0, stop=68630, step=1)

# 查看列名

df.columns

>>> Index(['行号', '仓库', '货号', '条码', '商品名称'], dtype='object')

# 几乎用不上吧

df.values

# 查看数据格式

df.dtypes

>>> 行号 int64

仓库 object

货号 int64

条码 object

# 计数:每个特征(列)的非空数量

df.count()

>>> 商品名称 68630

规格 6340

单位 67719

库存数量 68630

# 计数:对单个列(Series)的频数统计

df['仓库'].value_counts()

>>> 公司总部总仓库 2016

佛山南海万科店 938

深圳宝安兴业店 928

深圳宝安百年店 907

# 返回唯一值的数组

df['区域'].unique()

>>> array(['深圳', '东莞', '广州', '佛山', '江门', '成都', '四川'], dtype=object)

# 统计描述:可以对整个数据集(DataFrame),也可以对单个列(Series)

df.describe()

df['库存数量'].describe()

>>> count 68630.000000

mean 19.545230

std 248.819321

min -1600.000000

25% 2.000000

50% 5.000000

75% 14.000000

max 38080.000000

Name: 库存数量, dtype: float64

# 小技巧

df.describe().astype(np.int64).T

数据清洗

数据清洗

# 单列字段清洗-去空格

df['商品名称'] = df['商品名称'].map(lambda s : s.strip())

df['A']=df['A'].map(str.strip) # 去除两边空格

df['A']=df['A'].map(str.lstrip) # 去除左边空格

df['A']=df['A'].map(str.rstrip) # 去除右边空格

df['A']=df['A'].map(str.upper) # 转大写

df['A']=df['A'].map(str.lower) # 转小写

df['A']=df['A'].map(str.title) # 首字母大写

# 字段切分,并创建新特征

df.loc[:,"区域"] = df['仓库'].map(lambda s:s[0:2])

类型转换

# 转换某特征(列)的数据格式

df['行号'] = df['行号'].astype(float)

# 转化时间格式

df['time']=pd.to_datetime(df['time'])

缺失值

缺失值查看

# 缺失值判断(在原数据对象以T/F替换)

df.isnull()

df.notnull()

df['A'].isnull()

缺失值统计

# 缺失值计数方法

# 方法一

df['A'].isnull().value_counts()

>>> True 68629

False 1

Name: A, dtype: int64

# 方法二

df['A'].isnull().sum()

>>> 68629

df.isnull().sum()

>>> 仓库 0

货号 0

条码 2

规格 62290

缺失值删除

# 默认axi=0,how='any': 按行,任意一行有NaN就整列丢弃

df.dropna()

df.dropna(axis=1)

# 一行中全部为NaN的,才丢弃

df.driopna(how='all')

# 保留至少3个非空值的行:一行中有3个值是非空的就保留

df.dropna(thresh=3)

缺失值填充

# 整个数据集填充

df.fillna(0)

# 有针对性的填充

df.fillna({'性别':'男', '年龄':30})

重复值

# 返回布尔向量、矩阵

df['A'].duplicated()

df.duplicated()

# 整个实例一模一样才删除,默认保留第一行

df.drop_duplicates()

# 保留k1列中的唯一值的行,默认保留第一行

df.drop_duplicates(subset=["k1"])

# 保留 k1和k2 组合的唯一值的行,take_last=True 保留最后一行

df.drop_duplicates(subset=["k1","k2"], take_last=True)

值替换

# 一对一替换

# 将df的A列中 -999 全部替换成空值

df["A"].replace(-999, np.nan)

# 多对一替换

# -999和1000 均替换成空值

obj.replace([-999,1000], np.nan)

# 多对 一对一替换

# -999替换成空值,1000替换成0

obj.replace([-999,1000], [np.nan, 0])

# 同上,写法不同,更清晰

obj.replace({-999:np.nan, 1000:0})

# 有趣的写法

dataset_raw.loc[dataset_raw['workclass'] == 'Without-pay', 'workclass'] = 'Not Working'

修改表结构

一般数据分析需要修改表结构都是在列上动手脚,注意操作有以下几种

新增列

# 方式一

df['test'] = 0

# 方式二

df.loc[:,"区域"] = df['仓库'].map(lambda s:s[0:2])

# 方式三

df.loc[:,"is_bonus"]=1

df.loc[df['remarks']=='无奖金', 'is_bonus'] = 0

# 方式四

# 需求:创建一个新变量test2

# 1.petal_length>2 and petal_width>0.3 = 1

# 2.sepeal_length>6 and sepal_width>3 = 2 3.其他 = 0

df.loc[(df['petal_length']>2)&(df['petal_width']>0.3), 'test2'] = 1

df.loc[(df['sepal_length']>6)&(df['sepal_width']>3), 'test2'] = 2

删除列

# 丢弃指定的特征(列)

df.drop(['行号','条码'],

axis=1,

inplace=True)

删除行

# 删除特色的行用得少,一般使用切片

df.drop(index=['no1','no2'],

axis=0,

inplace=True)

df.drop(df.index[[0,1]],

axis=0,

inplace=True)

修改列名

df.rename(columns = {'年':'compute_year',

'月/季度':'compute_month',

'员工编号':'code',

'员工姓名':'name',

'职位':'position',

'体系':'system_name',

'运营单位':'op_unit_name',

'区域':'sub_area_name',

'部门名称':'dept_name',

'员工所属小组': 'sub_dept_name'},

inplace=True)

数据分组(数值变量)

# cut()数据分组,以连续值变量分组创建新特征

bins = [0, 5, 10, 15, 20] # 切分的边界

group_names = ['A', 'B', 'C', 'D'] # 每组的标签名

df['new'] = pd.cut(df['old'], bins, labels=group_names) # new就是分组新特征

# qcut只要指定切分个数即可

df.qcut(df['年龄'],4)

数据分列(分类变量)

这个操作和Excel中的分列功能很像,在原始数据表中grade列中包含了两个层级的用户等级信息,现在我们通过数据分列将分级信息进行拆分。数据分列操作使用的是split函数,下面是具体的代码和分列后的结果。

grade_split = pd.DataFrame((x.split('-') for x in loandata.grade),

index=loandata.index,

columns=['grade','sub_grade'])

完成数据分列操作后,使用merge函数将数据匹配会原始数据表,这个操作类似Excel中的Vlookup函数的功能。通过匹配原始数据表中包括了分列后的等级信息

loandata=pd.merge(loandata,grade_split,right_index=True, left_index=True)

设置索引

# 将列转化为索引

# 将columns中的其中两列:race和sex设置索引,race为一级,sex为二级

# inplace=True 在原数据集上修改的

# 默认情况下,设置成索引的列会从DataFrame中移除, drop=False将其保留下来

adult.set_index(['race','sex'], inplace = True)

# 取消列索引设置,并自动填充索引

adult.reset_index(level=None, drop=Fasle, inplace=False)

# 索引重塑

df.stack()

df.unstack()

排序

df.b(by=['code'], ascending=False, na_position='first')

df.sort_values(by=['code', 'name'], ascending=False, na_position='first')

# 缺失值NaN默认是排在最后后的,na_position='first'设置为排在最前面

数据筛选/切片

[]

isin

loc

iloc

ix

contains

# []只能对 行(row/index) 切片,前闭后开

df[0:3]

df[:4]

df[4:]

# where布尔查找,建立在[]基础之上

df[df["A"]>7]

# 并

df.loc[(df['petal_length']>2)&(df['petal_width']>0.3)]

# 或

df.loc[(df['petal_length']>2)|(df['petal_width']>0.3)]

# isin()

# 返回布尔值

df["A"].isin([1,2,3])

df.loc[df['sepal_length'].isin([5.8,5.1])]

# loc :根据名称Label切片

# df.loc[A,B] A是行范围,B是列范围

df.loc[:, ['petal_length','petal_width']]

df.loc[1:4, ['petal_length','petal_width']]

df.loc[['no1','no2'], ['petal_length','petal_width']]

# iloc:切位置,以序列号去切

df.iloc[1:4,:]

# ix:混切

# 名称和位置混切,但效率低,少用

df1.ix[0:3,['sepal_length','petal_width']]

# contains()模糊匹配

# 使用DataFrame模糊筛选数据(类似SQL中的LIKE)

# 使用正则表达式进行模糊匹配,*匹配0或无限次,?匹配0或1次

df_obj[df_obj['套餐'].str.contains(r'.*?语音CDMA.*')]

# 下面两句效果一致

df[df['商品名称'].str.contains("四件套")]

df[df['商品名称'].str.contains(r".*四件套.*")]

多表拼接

merge 合并

pandas.merge可根据一个或多个键将不同DataFrame中的行合并起来

# 在未指定连接键的情况下,merge会将重叠列的列名当做键

pd.merge(left, right)

# 指定“on”作为连接键,left和right两个DataFrame必须同时存在“on”列,连接键也可N对N(少用)

pd.merge(left, right, on="key")

pd.merge(left, right, on=["key1", "key2"])

# 指定left的连接键为“lkey”,right的连接键为“rkey”

pd.merge(left, right, left_on="lkey", right_on="rkey")

# suffixes:用于追加到重叠列名的末尾,默认为("_x", "_y")

pd.merge(left, right, on="key", suffixes=("_left", "_right"))

# 指定连接方式:“inner”(默认),“left”,“right”,“outer”

pd.merge(left, right, how="outer")

多对多连接产生的是行的笛卡尔积

常用方式:连接方式为“left”,right的连接键要唯一(去除重复值),通过right的数据补全left的数据索引上的合并(可用join代替,而且join更方便)

当DataFrame的连接键位于其索引中,可以使用 left_index=True 和 right_index=True

# 索引和索引连接

pd.merge(left, right, left_index=True, right_index=True)

# "key"和索引连接

pd.merge(left, right, left_on="key", right_index=True)

# 层次化索引

pd.merge(left, right, left_on=["key1", "key2"], right_index=True)

join 连接

DataFrame的join实例方法,是为了方便实现索引合并

# 用left的索引和right的索引进行merge

left.join(right)

# 用left的索引和right的“key”进行merge

left.join(right, on="key")

# 层次化索引

left.join(right, on=["key1", "key"])

# join可以合并两张以上的表,而merge只能合并两张表

left.join([right1, right2], how="outer")

concat 轴向连接

pandas.concat可以沿着一条轴将多个表对象堆叠到一起:因为模式how模式是“outer”

# 默认 axis=0 上下拼接,列column重复的会自动合并

pd.concat([df1, df2], axis=0)

# axis=1 左右拼接,行raw/index重复的会自动合并

pd.concat([df1, df2], axis=1)

# 忽略df1和df2原来的index,重新给新的DataFrame设置从0开始的index

pd.concat([df1,df2], ignore_index=True)

append

使用场景:表头一致的多张表,进行连接(上下连接)

df1.append(df2).append(df3)

combin_first 数据填补

使用场景:有两张表left和right,一般要求它们的表格结构一致,数据量也一致,使用right的数据去填补left的数据缺漏

如果在同一位置left与right数据不一致,保留left的数据

df1.combin_first(df2)

数据聚合&分组运算

groupby

# 单层分组

df.groupby('区域')

# 多层分组

df.groupby(['A','B'])

# 每个分组记录的计数

df.groupby('区域').size()

>>> 区域

东莞 7528

中山 520

佛山 5632

...

dtype: int64

# 分组数

len(df.groupby('区域'))

>>> 7

aggregate

grouped = df.groupby(['A','B'])

# 对一个特征一次求得多个统计数

grouped['age'].agg([np.sum, np.mean, np.std])

# 对单一属性统计可以改列名

grouped['age'].agg({"求和":np.sum,"求平均数":np.mean})

# 对不同属性求不同的统计数

grouped.agg({'age':np.mean,'fnlwgt':np.sum})

filter

# filter()

# 过滤分组计数少于1000的分组,在把分组计数大于1000的分组整合成一个DataFrame返回

con1 = lambda s : len(s) > 1000

df1 = grouped.filter(con1)

# 过滤分组age均值小于30的分组

con2 = lambda s : s['age'].mean()>30

df2 = grouped3.filter(con2)

tansformation

# tansformation()

# 会返回一个数据集,这个数据集与group具有相同的索引以及大小 相当分组处理后合并

# 举例说明对数据集进行标准化:

zscore = lambda s : (s - s.mean())/s.std()

df = grouped.transform(zscore)

数据透视表

crosstab

# crosstab() 一般只用与计数的数据透视表

pd.crosstab(index= df['A'],

columns = [df['B'],df['C']],

margins =True,

dropn=True)

pivot/pivot_table

# Produce 'pivot' table based on 3 columns of this DataFrame.

# Uses unique values from index / columns and fills with values.

# 感觉能使用的场景很少,因为不重复

df.pivot(index, columns, values)

df.pivot_table(values=None,

index=None,

columns=None,

aggfunc='mean',

fill_value=None,

margins=False,

dropna=True,

margins_name='All')

# 需求: index 是A ,columns 是 B,C, 我要求E的平均数并且有边

pd.pivot_table(df,

values = 'E',

index = 'A',

columns = ['B','C'],

aggfunc = [np.mean,np.sum],

margins = True)

时间序列

时间格式转化

# 转化时间格式

df['time']=pd.to_datetime(df['time'])

时间索引操作

哑编码

pd.get_dummies(data,

prefix=None,

prefix_sep='_',

dummy_na=False,

columns=None,

sparse=False,

drop_first=False)

数据导出

pd.to_csv("XXX.csv",index=False)

from sqlalchemy import create_engine

engine = create_engine('mssql+pymssql://zxadmin:Zx!@#$8888@172.17.180.113/BS_KF')

pd.io.sql.to_sql(df,'payroll',engine,if_exists='append',index=False,chunksize=10000)

数据入库

# pd 1.9以后的版本,除了sqllite,均需要通过sqlalchemy来设置

from sqlalchemy import create_engine

engine = create_engine('mssql+pymssql://zxadmin:Zx!@#$8888@172.17.180.113:8000/BS_KF')

# append:如果表存在,则将数据添加到这个表的后面

# fail:如果表存在就不操作

# replace:如果存在表,删了,重建

pd.io.sql.to_sql(df,'table_name',engine,if_exists='append',index=False,chunksize=10000)

# 关闭连接

engine.dispose()

技巧

数据集概览

# 整体概况

def birdview(data):

print(data.shape)

d = {}

for col in data.columns:

if len(list(data[col].unique()))<30:

d[col]= str(list(data[col].unique()))

else:

d[col]= "too much"

r = pd.DataFrame(pd.Series(d),columns=['values'])\

.join(pd.DataFrame(data.dtypes,columns=['type']))\

.join(pd.DataFrame(data.count(),columns=['count']))\

.join(pd.DataFrame(data.isnull().sum(),columns=['isnull']))

return r.sort_values(by=['values','type',])

def catview(data):

print("定性数据概况")

for c in data.columns:

print(c)

print(dict(df[c].value_counts()))

def valueview(data):

print("定值数据概况")

return data.describe().T\

.join(pd.DataFrame(data.skew(),columns=['skew']))\

.join(pd.DataFrame(data.kurt(),columns=['kurt']))

长宽表转换

宽表转换为长表

# 方法一:先用set_index,再用stack,然后还有rename修改下列名

df.set_index(['Company','Name'], inplace = True).stack().reset_index()

# 方法二:melt

df.melt(id_vars=['Company','Name'],

var_name='Year',

value_name='Sale')

长表转换为宽表

df.pivot_table(index=['Company','Name'], columns='Year', values='Sale')

行列互换

df.T

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值