关于 Python 之 Pandas 的总结

通用

conda update pandas #升级panda

pd.__version__ #显示版本

导包

import numpy as np
import pandas as pd
from pandas import DataFrame, Series

格式控制

pd.set_option('display.max_columns', 10) # 最多显示 10 列,中间用…代替

pd.set_option('display.width', 120) # 每行最多显示的字符数,超过时折行

pd.set_option('display.max_rows', 30) # 每个表最多显示 30 行

pd.set_option('precision', 2) # 显示精度(小数点后 2 位)

数据结构

Series

带标签的一维数组

基本操作

#构造
s = Series(np.random.rand(4)) #4个0~1的数
s = Series([10,20,30])  #默认0~n
s = Series([10,20,30],index=['a','b','c'])   
s = Series([10,20,30],index=list('abc'))
s = Series({
    
    'a':10,'b':20,'c':30})

#访问
s['a']   #自定义之后也可用s[0]
s.a
s['a':'c'] #切片 包含尾巴数据
s[0:2]  #切片 不包含尾巴数据

#常用函数
s.sum() 
s.mean()  #均值
s.median() #中位数
s.size  #数据个数 无需括号
s.count()  #非空数据个数
s.unique()  #不重复的数据值
s.value_counts() #各数据出现次数
s.head(n) #头n行
s.tail(n) #尾n行
s.take([]) #按指定索引取下标

#修改 Series类似于字典,obj[标签]=x,若标签存在则修改,不存在则添加
s.index = ['d','e','f'] #只能一次性修改 不能单独修改一个index


#运算 标签自动对齐,不匹配显示NaN

#数据和索引
s.values
s.index
s.index.value_counts()

#name
s.index.name=' ' #设置索引的name属性
s.name=' '  #设置数据的name属性

DataFrame

带标签的二维数组

数据库,方便读取 清洗 统计 数据。

基本操作

#构造 
#间接字典构造
data = {
    
    'apple': [1100,1050,1200], 'huawei': [1250,1300,1328], 'oppo': [800,850,750]}
df = DataFrame(data, index=['一月', '二月', '三月'])
#直接字典构造
df = DataFrame({
    
    'apple': {
    
    '一月':1100, '二月':1050, '三月':1200},
 'huawei': {
    
    '一月':1250, '二月':1300, '三月':1328},'oppo' : {
    
    '一月':800, '二月':850, '三月':750}})
#numpy构造
df = DataFrame(np.arange(12).reshape(3,4),index=['a','b','c'],columns=['c1','c2','c3','c4'])

#显示
df.index  
df.columns
df.describe()  #快速得到df的每列数据个数 均值 标准差 最小值 最大值及分位点的对应值

#修改
df.index=[]
df.columns=[]
df[列名]= [] #增加列

#访问
df.info() #表的基本信息
df.head(n)
df.tail(n) #尾n行
#列的访问
df['apple']
df.apple
#行的访问
#tip:[]内的条件要用& | ~  而不是 and or not
df[(df.c1 > 3) & (df.c2 > 5)] # 按条件访问,c1 列>3 且 c2 列>5
df.loc['a'] # loc 基于标签,取行标签'a'对应的行,得到一个 Series
df.loc['a':'b', 'c1':'c2'] # 取数据块[行标签:列标签]
df.loc[:, 'c2':'c3'] # 取数据块[行标签:列标签]
df.iloc[0:2] # iloc 基于整数下标,取第 0、1(不含第 2)行数据

#at  iat  query
df.iat[1,2]  #第1行第2列的值
df.at['b','c3'] #基于行/列的标签
df.query('c1>2 and c2>6')

运算操作

nan

numpy的话是返回nan,而panda是直接忽略nan对有效数据进行计算

#可在函数括号添加参数 skipna=False 代表不能忽略nan
s=Series( np.array([1, 5, np.nan, np.nan, 10]) )

df = pd.DataFrame(np.arange(12).reshape(4, 3), index=list('abcd'), columns=list('xyz'))

s.isnull() #判断每个值是否为nan
s.isnull().sum()

s.notnull() #判断是否为非nan

df.dropna() #含nan的行均被删除 即默认axis=0 
df.dropna(how='all') #表示行的所有数据为nan才会被删除
df.dropna(thresh=2) #nan个数>=2才删除

df.fillna(0) #nan填充0
df.fillna(method='ffill') #用前面的非nan值填充 bfill为后面的非nan
df.fillna(value=df.mean()) #用均值填充

对齐

DataFrame 和 Series 之间的运算默认将 Series 的索引匹配到 DataFrame 的列,然后沿着行方向一直向下广播。如果某个索引值在 DataFrame 的列或 Series 的索引中找不到,那么参与运算的两个对象就会被重新索引以形成并集。

即 df 的每一行/列 加上 s 代表的值。

两个数据框运算时,在行、列索引上都要对齐,对不齐为nan。

通用函数

df.sum()  #默认axis=0 给出列的和   axis=1则给出行的和
df.sum().sum()

#apply 应用到整行、整列
df.apply(lambda x : x.max()-x.min()) #每列上求最大值-最小值
df.apply(lambda x : x-x.mean(),axis=1) # 计算每行数据与均值的差

#applymap 单个数据
df.applymap(lambda x : str(x)*2)

文件操作

CSV文件

#GBK是windows的中文编码字符集 故涉及到中文均使用GBK
df.to_csv('xxx.csv',encoding='GBK') #GBK可以写成cp396
!type xxx

#index_col=0指定第0列作为标签
df = pd.read_csv('xxx.csv',index_col=0,encoding='GBK')

#可以自己指定列名,如果没有中文可以不用指定GBK
df = pd.read_csv("xxx.csv", names=['apple', 'huawei', 'oppo'])

#header=None  读取的时候不指定列名 
#sep是读取间隔 \s+是正则表达式 匹配多个空格
df = pd.read_csv(' ',header=None,sep='\s+')
df.columns=[]
df.index=[]

#skiprows 跳过不需要读取的行
pd.read_csv("数据文件名", skiprows=[0, 2]) # 跳过第 0, 2 行
pd.read_csv("数据文件名", skiprows=4 ) # 跳过前 4 行

# 跳过尾部的 2 行
pd.read_csv("数据文件名", skipfooter=2, engine = 'python') 

#只读取前n行
pd.read_csv("数据文件名", nrows=10) # 只读取前 10 行数据

#处理日期 
pd.read_csv('stock.txt', parse_dates=['交易日'],encoding='cp936', 
sep='\s+', index_col='交易日')

Excel

# 默认读第 1 个工作表,第 1 行作为列名,A 列(第 0 列)作为标签
df1 = pd.read_excel("mobile.xlsx", index_col=0) # 读 Excel 文件
# sheet_name 指定读某个工作表
df2 = pd.read_excel("mobile.xlsx", sheet_name='二季度')

df1.to_excel("a1.xlsx") # 写入 Excel 文件

#多数据处理   如果没有with的话是覆盖
from pandas import ExcelWriter
with ExcelWriter("test.xlsx") as writer:
	df1.to_excel(writer, sheet_name='一季度')
	df2.to_excel(writer, sheet_name='二季度')
    
    
import pandas as pd
f = pd.ExcelFile('stock.xlsx')
f.sheet_names  # 获取工作表名称
 
lst=[ ]
data = pd.DataFrame()
for i in f.sheet_names:
    df = pd.read_excel('stock.xlsx', sheet_name=i)
    lst.append(df)

HDF5

# 若 store.h5 文件不存在,则先创建;若已存在,则打开此文件
store = pd.HDFStore('store.h5') 
store['dfa'] = df1 # 将 df1 保存到文件中,键名 dfa
store['dfb'] = df2 # 将 df2 保存到文件中,键名 dfb
store.close() # 关闭文件

store = pd.HDFStore('store.h5') # 打开文件 
df3 = store['dfa'] # 根据 dfa 键名取出数据
df4 = store['dfb'] # 根据 dfb 键名取出数据

数据整理

ignore_index=True:

这个是 pandas 内部的语法要求。添加时扩号内部的会被视为series 。当将series 添加到 dataframe 时,pandas 要求必须加上 ignore_index=True , 这样就不核对列索引名是否完全一致。即使列名不一致,也允许插入。

inplace=True

表示修改原数据框

#1.行的插入和删除
df.drop(行标签) #返回删除行后的新数据框,原数据框不变

df.append(ignore_indexeTrue) #末尾插入  

#2.列的插入和删除
df[' ']=[ ] #直接赋值
df.insert(4, '平均成绩', (df.成绩 1 + df.成绩 2) / 2 ) #指定插入到第几列,直接改变原数据框

df.drop(列名,axis=1,inplace=True) #返回删除列后的新数据框

df.pop(列名) #删除并返回某列,直接改变原数据框
del df[列名] #直接改变原数据框

#3.索引处理
df.reindex([],inplace=True) #重索引
df.rename({
    
    }) #更改列名
df.reset_index(inplace=True) #将索引列变为数据列
df.set_index(列名) #将数据列变为索引列

#4.重复值处理
df.duplicated() #检测重复值,返回布尔数组
df.drop_duplicates() #删除重复值 可指定列

排序和排名

排序

ascending=False : 逆序排序

axis :按照行/列排序

by : 指定行/列排序

s = Series([2, 5, 1], index=['d', 'a', 'b'])
s.sort_index() # 按索引'a b d'排序,返回新对象,并不改变原对象 s.sort_values() # 按数据值 1 2 5 排序

排名

method=‘first’ : 表示排名相同时不计算平均名次,而是以数据出

现的先后顺序排列

ascending=False : 逆序排序

 s.rank() # 排名,默认按数据值升序排名
 s.rank(method='first') # 指定名次号的生成方法为 first

数据框连接

df1 和 df2 有同名列 color,pd.merge()自动将同名列作为连接键,横向连接两个数据框的 color键值相等的行。连接时,会丢弃原 dataframe 的索引。

两个数据框的列名不同时,用 left_on 和 right_on 参数分别指定。下例中指定 c1, c2 列为键,表示当 df1 表的 c1 列值等于 df2 表的 c2 列值时满足连接条件。因为 df1, df2 中的 color 列名相同,所以连接后自动加上后缀_x, _y 进行区分。

对于 how : left right outer 等同于数据库的左/右外连接 外连接 。

df1 = DataFrame({
    
    'color':['r', 'b', 'w', 'w'], 'c1':range(4)})
df2 = DataFrame({
    
    'color':['b', 'w', 'b'], 'c2':range(2, 5)})

pd.merge(df1, df2) # 或写为 pd.merge(df1, df2, on='color')

pd.merge(df1, df2, left_on='c1', right_on='c2')

pd.merge(df1, df2, left_index=True, right_index=True) # 将索引用于连接键

pd.concat([df1, df2], ignore_index=True) # 默认沿纵向合并,行数增加
pd.concat([df1, df2], axis=1) # axis=1 沿横向合并,列数增加

数据分段

score=np.random.randint(30, 100, size=100) # 生成 100 个随机整数
bins=[0, 59, 70, 85, 100] # 定义区间段
labels=['不及格', '中', '良', '优'] # 设置各段的标识文字
scut=pd.cut(score, bins, labels=labels) # 将 score 按 bins 分段

type(scut) # 查看 scut 的数据类型
pd.value_counts(scut) # 统计各类别的数据个数

多级索引

slice(None): 多级索引的切片语法

In: mindex = pd.Index([('A', 'r'), ('A', 'g'), ('B', 'r'), ('B', 'g')], name=['product', 'color']) 
# 创建多级索引
# 利用多级索引创建数据框
df = DataFrame(np.arange(2, 10).reshape(4, 2), index=mindex, columns=['一月','二月'])

df.index

df.loc['B']  #访问B类产品

df.loc[('B','r')]  #访问B类产品的r组产品

df.loc[(slice(None),'r'),:] #查看所有r产品

df.loc['A'].sum().sum() #求A总数

df.loc[(slice(None), 'r'), :].sum().sum() #求r总数

df2 = df.unstack() # 默认将最内层的 1 级行索引转为列索引

df.stack() # 将列索引(即列名)变为行索引

字符串处理

s = Series(['Beauty and the Beast', 'Captain America: Civil War', 
'Jurassic World', 'Toy Story'])

s.str.len() # 返回字符串长度
s.str.split() # 分割字符串
s.str[:6] # 字符串切片
s.str.contains('War')# 测试电影名中是否包含 War
s.str.replace(' ', '-') # 字符替换,用横线-替换空格

分组统计

df = pd.DataFrame({
    
    'color': ['red', 'white', 'black', 'red', 'black', 'red'], 'size':
['s','m','b','s','m','b'], 'price': [10, 11, 12, 20, 21, 22], 'quantity': [1, 2, 3, 3, 4, 5]})

g = df.groupby('color')

for name, group in g:
 print(name) # 输出组名
 print(group) # 组内容

g.ngroups #分组数目属性
g.size() #列出每个分组所含的数据个数
g.sum(), g.mean(), g.std() #对每组求和、均值、标准差
g.groups #列出每个分组包含的数据索引编号
g.head(n), g.nth(n) #列出分组的前 n 个数据, 第 n 个数据
g.describe() #对分组进行统计,返回一组常用统计量
g.agg([函数 1, 函数 2]) #对分组数据按指定函数进行统计
g.get_group('black') # 指定返回 black 组数据

#数据透视表
df.pivot_table(index='color', columns='size', values='quantity', aggfunc='sum')
#参数表中 index 指定分组索引列,columns 指定列名,values 指定要计算的列,aggfunc 指定计算方法。例如,'sum'是求和,'mean'是求平均值,'count'是计数。

时间序列

pd.to_datetime('2019-2-20')  # 不同格式的日期字符串都可转换

today = pd.datetime.now() # 生成今天的日期
today + pd.DateOffset(days=3) # 后推 3 天
today + pd.DateOffset(years=1, months=6) # 后推 1 年 6 个月

df.index = pd.to_datetime(df.index) # 将索引的数据类型转为日期型

pd.date_range(起始日期, 结束日期, periods=周期数, freq=日期频率)
eg:
pd.date_range('2019-02-01', '2019-02-28') # 默认频率为 1 天
s = pd.date_range('2019-01-01', periods=6, freq='3D') 
# 每 3 天 1 个日期,共 6 个数据

s.shift(1) # 后移一个数据位
s.shift(-2) # 前移两个数据位

s - s.shift(1) # 计算后一天相对前一天的变动值

# 计算变动百分比,map 方法将每个值按 format 指定的格式转换为百分比
((s - s.shift(1)) / s.shift(1)).map(lambda x: format(x, '.2%'))
#freq 参数表
H 时
T 分
S 秒
L 毫秒
D 日历日(即每天,此为默认值) B 商业日(只含周一至周五,不含周六、日)
W 周
M 月底(如 131 日,228 日,630 日)
MS 月初(如 11 日,21 日,61 日)
Q 季末(如 331 日,630 日)
QS 季初(如 11 日,41 日)
A 年底
AS 年初

时间频率变换

np.random.seed(7)
dates = pd.date_range('2018-1-1', periods=365)
s = Series(np.random.randn(365), index=dates) # 生成 2018 年全年的随机数据
s['2018-1'] # 选取2018年1月的数据
s['2018-02':'2018-04'] # 选取 2018 年 2 月至 4 月的数据

#按1个月的频率重采样
In: s.resample("1M").mean() # 按月求均值

s.resample("10D").sum() # 每 10 天求和

s.resample("10D").agg([np.max, np.min])

Panel

带标签的三维数组

猜你喜欢

转载自blog.csdn.net/JiangHxin/article/details/108347965