pandas是Python的核心数据分析支持库,提供了快速、灵活、明确的数据结构,能够简单、直观地处理关系型、标记型数据。pandas主要数据结构是一维数据Series和二维数据DataFrame,这两种数据结构足以处理金融、统计、工程等领域中的大多数案例。处理数据的一般步骤是:数据整理与清洗、数据分析与建模、数据可视化与制表。

import numpy as np
import pandas as pd
from sqlalchemy import create_engine
  1. 数据结构
# 无论是numpy中的NAN,还是Python的None在pandas中都以缺失数据NaN对待
li = [0, 1, 3, 7, 9, np.NAN, None, 1024, 128]
# Series 用列表生成Series时,Pandas默认自动生成整数索引,也可以指定索引
s1 = pd.Series(data=1) 
s2 = pd.Series(data=1, index=list('abcdehi'), dtype='float32')
s3 = pd.Series(data={'a':99, 'b':137, 'c':149}, name='python_score')
print(s1, s2, s3)
# DataFrame是由多种类型的列构成的二维标签数据结构,类似于Excel、SQL表或者Series对象构成的字典
df1 = pd.DataFrame(data={'Python':[99, 107, 122], 'Math':[110, 128, 88], 'Java':[120, 48, 66]},
index = ['张三', '李四', '王五'])
# index是行索引,columns是列索引
df2 = pd.DataFrame(data=np.random.randint(0, 155, size=(5,3)), index=['张三', '李四', '王五', '赵六', '马奇'],
columns = ['Python', 'Math', 'Java'])
print(df1, df2)
# 查看DataFrame的常用属性、概览和信息统计
df = pd.DataFrame(data=np.random.randint(0, 151, size=(150, 3)), index = None, columns=['A', 'B', 'C'])
df.head(10) # 显式前10行,默认是5行
df.tail(10) # 显式后10行
df.shape  # 查看行数和列数
df.dtypes # 查看数据类型
df.index  # 查看行索引
df.values  # 对象值,二维数组
df.describe() # 查看数据值列的汇总统计,计数,平均值,标准差,最小值,四分位数,最大值
df.info() # 查看列索引,数据类型,非空计数和内存信息
  1. 数据的输入输出
# csv
df = pd.DataFrame(data=np.random.randint(0, 50, size=[50, 5]), columns=['IT', '生物', '化工', '军人', '教师'])
# 保存到文件,分隔符为分号,保存列索引、行索引
df.to_csv('./salary.csv', sep=";", header=True, index=True)
pd.read_csv('./salary.csv', sep=";", header=[0], index_col=0)
pd.read_table('./salary.csv', sep=";", header=[0], index_col=1)
# Excel
# 使用pip安装xlrd、xlwt,xlrd版本2.0.1不支持xlsx文件的读取,使用更低版本的xlrd解决pip install xlrd==1.2.0
df1 = pd.DataFrame(data=np.random.randint(0, 50, size=[50, 5]), columns=['IT', '生物', '化工', '军人', '教师'])
df2 = pd.DataFrame(data=np.random.randint(0, 50, size=[150,3]), columns=['Python', 'Java', 'C++'])
df1.to_excel('./salary.xls', sheet_name='salary', header=True, index=False)
pd.read_excel('./salary.xls', 
    sheet_name=0,  # 读取哪个工作表,默认第一个
    header=0, # 使用第一行数据作为索引列
    names=list('ABCDE'), # 替换行索引
    index_col=1) # 指定行索引,B作为行索引
with pd.ExcelWriter('./data.xlsx') as writer:
    df1.to_excel(writer, sheet_name='salary', index=False)
    df2.to_excel(writer, sheet_name='score', index=False)
pd.read_excel('./data.xlsx', sheet_name='salary')
# SQL
# 使用pip安装sqlalchemy、pymysql,SQLAlchemy提供了SQL⼯具包及对象关系映射(ORM)⼯具
df = pd.DataFrame(data=np.random.randint(0, 50, size=[150,3]), columns=['Python', 'Java', 'C++'])
conn = create_engine('mysql+pymysql://root:root@localhost/test?charset=UTF8MB4')
# 数据保存到score表中,指定第一列名称为id
df.to_sql('score', conn, if_exists='append', index=True, index_label='id')
pd.read_sql('select * from score limit 10', conn, index_col='Python')
  1. 数据的选区
# 数据获取 index指定行标签,columns指定列标签
df = pd.DataFrame(data=np.random.randint(0, 150, size=[10,3]), index=list('ABCDEFGHIJ'), columns=['Python', 'Java', 'Spring'])
df.Python # 查看所在列数据,或者df['Python']
df[['Python', 'Java']]  # 获取多列数据
df[1:3] # 行切片操作
# 使用loc[]进行数据获取,loc通过行列标签进行索引取数操作
df.loc[['A','B']] #选取行标签
df.loc[['A','B'],['Python','Keras']] #根据行列标签选取对饮数据
df.loc[:,['Python','Keras']] #保留所有行
df.loc[::2,['Python','Keras']] #每隔2行取出一行数据
df.loc['A',['Python','Keras']] #根据行标签选取出对应数据
# 使用iloc[]进行数据获取,ioc通过行列整数标签进行索引取数操作
df.iloc[2:4] # 利用整数行切片操作与Numpy相似
df.iloc[1:3,1:2] # 利用整数对行和列进行切片
df.iloc[1:3:]  # 行切片
df.iloc[:,0:1] # 列切片
# Boolean索引
cond1 = df.Python > 100 # 判断Python分数是否⼤于100,返回值是boolean类型的Series
df[cond1] # 返回Python分数⼤于100分的⽤户所有考试科⽬数据
cond2 = (df.Python > 50) & (df['Keras'] > 50) # &与运算
df[cond2] # 返回Python和Keras同时⼤于50分的⽤户的所有考试科⽬数据
df[df > 50]# 选择DataFrame中满⾜条件的值,如果满⾜返回值,不然返回空数据NaN
df[df.index.isin(['A','C','F'])] # isin判断是否在数组中,返回也是boolean类型值
  1. 数据集成
# concat数据串联
df1 = pd.DataFrame(np.random.randint(1,151,size=10), index = list('ABCDEFGHIJ'), columns=['Science'])
df2 = pd.DataFrame(data = np.random.randint(0,150,size = [10,3]), index = list('KLMNOPQRST'), columns=['Python','Java','PHP']) 
pd.concat([df, df2], axis=0) # df2串联拼接到df的下方,空值为NaN
pd.concat([df, df1], axis=1) # df1串联拼接到df的右侧
df.apped(df1)  # 在df后面追加df1
# 插入 insert()插入一列,插入的这一列的长度必须和被插入的行数长度相等
df.insert(loc=1, column='C++', value=np.random.randint(0, 151, size=(10)))
# 数据的链接 数据集的合并或连接运算是通过一个或多个键将数据链接起来的
df1 = pd.DataFrame(data = {'sex':np.random.randint(0,2,size=6),'name':['小刘','小张','小华','小李','小姜','小赵']})
df2 = pd.DataFrame(data = {'score':np.random.randint(90,151,size=6),'name':['小刘','小张','小华','小李','小姜','小明']})
pd.merge(df1, df2) # 内连接,使用merge合并中merge自动去除了空数据
pd.merge(df1, df2, how='left')  # 左连接
pd.merge(df1, df2, how='right') # 右连接
  1. 数据清洗
# duplicated筛选重复数据,自上而下的顺序进行筛选如果行值相同就返回True
df2 = pd.DataFrame(data = {'name':['小刘','小张','小华','小李','小姜','小张'], 'Sex':[0,1,0,1,0,1], 'Score':[88,100,68,90,80,100]})
df2.duplicated() # 检查重复值 以Boolean形式进行输出展示
df2.duplicated().sum() # 打印有多少重复值
df2[df2.duplicated()] # 打印重复值
df2[df2.duplicated()==False] # 打印非重复值
df2.drop_duplicates() # 删除重复值(此操作并不是在数据源本身进行删除操作)
df2.drop_duplicates(inplace=True) # 删除重复值(此操作是在数据源本身进行删除操作)
# 过滤空数据
df2.isnull() # 检查是否存在空值,None或NaN
df2.dropna(how='any') # 删除空数据,此操作并不是在数据源本身进行删除操作
df2.dropna(how='any', inplace=True) # 删除空数据,此操作并在数据源本身进行删除操作
df2.fillna(value='小风') # 填充空数据,此操作并不是在数据源本身进行删除操作
df2.fillna(value='小风', inplace=True) # 填充空数据,此操作在数据源本身进行删除操作
# 过滤指定行或列
del df2['Sex'] # 删除Sex列
df2.drop(labels=['Sex'], axis=1) # 删除指定列
df2.drop(labels=[0,1,5], axis=0) # 删除指定行
# filter函数选取保留的数据过滤其他数据
df2.filter(items=['Name', 'Score']) # 保留指定列
df2.filter(like='S', axis=1) # 保留列标签包含S的列
df2.filter(regex='S$', axis=1) # 正则方式进行筛选
  1. 数据转换
# rename和replace的转换标签元素
df2.rename(index={0:10, 1:11}, columns={'name':'StName'}) # 将行索引0换成10、1换成11,列索引换成StName
df2.replace(100, 102) # 将所有的100替换成102
df2.replace([88, 68], 78) # 将所有的88、68替换成78
df2.replace({'小华':'小丽', None:'小华'}) # 根据字典的键值对进行替换
df2.replace({'Sex':1}, 1024) # 将Sex列的1替换为1024
# apply和transform都能针对DataFrame的特征进行计算,apply不能直接使用python的内置函数
df = pd.DataFrame(data = np.random.randint(0,150,size = [10,3]),index = list('ABCDEFGHIJ'),columns=['Python','C','PHP'])
df.Python.apply(lambda x:True if x>50 else False) # 选取python学科中的大于50分的数据
df.apply(lambda x: x.median(), axis=0) # 列的中位数
df['Python'].transform([np.sqrt, np.log10]) # 对单列数据处理做开平方和对数运算
  1. 数据重塑
df = pd.DataFrame(data=np.random.randint(0,150,size=[20,3]), index=pd.MultiIndex.from_product([list('ABCDEFHIJK'), ['一期', '二期']]), columns=['Python', 'C', 'Java'])
df.unstack(level=1) # 行作列
df.stack() # 列作行
df.mean(level=1) # 各学科每期平均分
df.mean(level=0) # 各学员平均分
df.mean() # 各科平均分
  1. 统计方法
df = pd.DataFrame(data = np.random.randint(0,150,size = [10,3]),index = list('ABCDEFGHIJ'),columns=['Python','C','Java'])
df.count() # 非NA值的数量
df.max(axis=0) # 轴0的最大值,即每一列最大值
df.min() # 默认计算轴0的最小值
df.median() # 中位数
df.sum() # 求和
df.mean(axis=1) # 计算每一行的平均值
df.quantile(q=[0.2, 0.5, 0.9]) # 分位数
df.describe() # 查看数值型列的汇总统计,计数、平均值、标准差、最⼩值、四分位数、最⼤值
df['Python'].value_counts() # 统计元素出现次数
df['C'].unique() # 去重
df.cumsum() # 累加
df.cumprod() # 累乘
df.std() # 标准差
df.var() # 方差
df.cummin() # 累积最小值
df.cummax() # 累积最大值
df.diff() # 计算差分
df.pct_change() # 计算百分比变化
df.cov() # 属性的协方差
df.Python.cov(df['C']) # Python和C的协方差
df.corr() # 所有属性相关性系数
df.corrwith(df['Java']) # 单一属性相关性系数
df['Python'].argmin() # 计算Python列的最小值位置
df['C'].argmax # 计算C列的最大值位置
df.idxmax() # 最大值索引标签
df.idxmin() # 最小值索引标签
  1. 排序
df = pd.DataFrame(data=np.random.randint(0, 150, size=[10, 3]), 
    index=list('ABCDEFGHIJ'),
    columns=['Python', 'PHP', 'Java'])
ran = np.random.permutation(10)
df = df.take(ran) # 随机排序行索引
df.sort_index(axis=0, ascending=True) # 按照行索引降序
df.sort_index(axis=1, ascending=True) # 按照列索引降序
df.sort_values(by='Python')           # 根据Python列的值降序排序
df.sort_values(by=['Python', 'PHP'])  # 先按照Python列排序再按照PHP列排序
large = df.nlargest(3, columns='PHP') # 根据属性PHP排序,返回最大3个数据
small = df.nsmallest(3, columns='Python') # 根据Python列排序后,返回最小3个数据
print(large, small)
  1. cut与qcut的分箱处理

cut函数对数据进行分箱处理的操作,就是把一段连续的值切分成若干段,每段的值看成一个分类。这个把连续值转换成离散值的过程,称为分箱处理,按照数值由大到小的顺序将数据分割成若干份,并且每组范围大致相等。qcut是按照变量的数量来对变量进行分割,尽量保证每个分组里变量的个数相同。

df['py_cut'] = pd.cut(df.Python, bins=4) # 按照范围分箱
df['php_cut'] = pd.cut(df['PHP'], bins=4)
df['q_评级'] = pd.qcut(df.Python, q=4, labels=['差', '中', '良', '优']) # 按照数据个数分组
df['c_评级'] = pd.cut(df.PHP, 
    bins=[0, 60, 90, 120, 150], # 分箱断点
    right=False,  # 左闭右开原则
    labels=['差', '中', '良', '优'])  # 分箱后分类