Pandas用法总结

Pandas用法总结

Pandas简介

Pandas是基于NumPy的一种工具,该工具是为了解决数据分析任务而创建的。Pandas纳入了大量库和一些标准的数据模型,提供了高效地操作大型数据库所需的工具。Pandas提供了大量能使我们快速便捷地处理数据的函数和方法。Pandas基于两种数据类型:series 和 dataframe

Series

Series是Pandas中最基本的对象,类似一维数组。事实上,Series基本上就是基于NumPy的数组对象来的,和NumPy的数组不同,Series能为数据自定义标签,也就是索引(index),然后通过索引来访问数组中的数据。用法总结如下:


Series对象的创建

# pandas 学习
import pandas as pd
from pandas import Series,DataFrame
import numpy as np

# 一维数组
sel = Series([1,2,3,4])
# 会同时打印索引和对应的元素
print(sel)

# 但通常我们会自己创建索引 index代表索引
# sel= Series(data=[1,2,3,4],index=['a','b','c','d'])
sel = Series(data=[1,2,3,4],index=list('abcd'))
print('数组:')
print(sel)
# 获取内容
print('数组值:',sel.values)
# 获取索引
print('数组下标',sel.index)
# 同时获取索引和值
print('同时获取索引和对应值',list(sel.iteritems()))

# 将字典转换为Series
dict = {'red':100,'back':400,'green':300,'pink':900}
se3 = Series(dict)
print(se3)

Series数据获取

# Series 数据获取

sel = Series(data = [1,2,3,4], index = list('abcd'))
print(sel)

# Series 对象同时支持位置和标签两种方式获取数据
print('索引下标:',sel['c'])
print('位置下标:',sel[2])

# 获取不连续的数据
print('索引下标:')
print(sel[['a','c']])
print('位置下标:')
print(sel[[1,3]])

# 可以使用切片 取数据
print('位置切片:') 
print(sel[1:3])        # 左包含右不包含
print('索引切片:')      
print(sel['b' : 'd'])    # 左右都包含

# 重新赋值索引的值
sel.index = list('dcba')
print(sel)
# reindex 重新索引,会返回一个新的Series(调用reindex将会重新排序,缺失值用NaN填补)
print(sel.reindex(['b','a','c','d','e']))

# drop() 丢弃指定轴上的项
sel = pd.Series(range(10,15))
print(sel)
# drop 
print(sel.drop([2,3]))

Series算术运算

# Series 进行算术运算
# 对 Series 的算术运算都是基于 index 来进行的
# 我们可以用 加减乘除(+,-,* ,/)这样的运算对两个 Series 进行运算
# pandas 根据索引 index 对响应的数据进行计算,结果将会以浮点数的形式储存,以避免丢失精度
# 如果 pandas 在 两个 Series 里找不到相同的 index ,对应的位置就返回一个空值 NaN
# series(data ,index) 第一个是数据 第二个是索引 感觉有点别扭
# 只有索引相同才进行计算,否则返回空值 NaN

series1 = pd.Series([1,2,3,4],['London','HongKong','HuBei','Lagos'])
series2 = pd.Series([1,3,6,4],['London','Accra','Lagos','Delhi'])

print(series1)
print('\n')
print(series2)
print('\n')
print(series1-series2)
print('\n')
print(series1+series2)
print('\n')
print(series1*series2)
print('\n')

# 同样也支持numpy 的数组运算
sel = Series(data=[1,6,3,5],index=list('abcd'))
print('原数组:')
print('\n')
print(sel)
print('\n')
print(sel[sel>3]) # 布尔数组过滤 值大于3
print('\n')
print(sel * 2) # 标量乘法
print('\n')
print(np.square(sel)) # 可以直接加入到numpy的数学函数 平方

DataFrame

DataFrame的创建

# DataFrame 的创建
# 二维数据结构(表格形式储存)
# 三个参数 data index columns 分别代表 数据 行索引 列索引
# 使用二维数组
df1 = DataFrame(np.random.randint(0,10,(4,4)),index=[1,2,3,4],columns=['a','b','c','d'])
print(df1)

运行结果:
a b c d
1 2 9 6 1
2 0 5 5 0
3 4 4 7 8
4 4 3 5 2


# 使用字典进行创建(行索引由index决定,列索引由字典的键决定)
dict = {
    'Province': ['Guangdong','Beijing','Qinghai','Fujian'],
    'pop': [1.3, 2.5, 1.1, 0.7],
    'year': [2018, 2018, 2018, 2018]
}
df2 = pd.DataFrame(dict,index=[1,2,3,4])
print(df2)

# 使用 from_dict
dict2 = {'a':[1,2,3],'b':[4,5,6]}
df6 = pd.DataFrame.from_dict(dict2)
print(df6)

# 索引相同的情况下,相同索引的值会相对应,缺少的值会添加NaN
data={
    'Name':pd.Series(['zs','ls','we'],index=['a','b','c']),
    'Age':pd.Series(['10','20','30','40'],index=['a','b','c','d']),
    'country':pd.Series(['中国','日本','韩国'],index=['a','c','b'])
}
df3 = pd.DataFrame(data)
print(df3)

# to_dict() 方法将DataFrame 对象转换为字典
dict = df3.to_dict()
print(dict)

运行结果:
Province pop year
1 Guangdong 1.3 2018
2 Beijing 2.5 2018
3 Qinghai 1.1 2018
4 Fujian 0.7 2018
a b
0 1 4
1 2 5
2 3 6
Name Age country
a zs 10 中国
b ls 20 韩国
c we 30 日本
d NaN 40 NaN


DataFrame对象常用属性

# DataFrame 常用属性
df_dict={
    'name':['James','Curry','Iversion'],
    'age':['18','20','19'],
    'national':['us','China','us']
}
df = pd.DataFrame(data=df_dict,index=['0','1','2'])
print(df)
print('\n')
# 获取行数和列数
print('DataFrame的大小:',df.shape)
# 获取行索引
print('获取DataFrame的行索引:',df.index.tolist())
# 获取列索引
print('获取DataFrame的列索引:',df.columns.tolist())
print('\n')
# 获取数据的类型
print('获取DataFrame的数据类型:')
print(df.dtypes)
print('\n')
# 获取数据的维度
print('获取数据的维度:',df.ndim)
print('\n')
# values属性 也会以二维 ndarray 的形式返回 DataFrame 的数据
print('df的values属性:')
print(df.values)
print('\n')

# 展示df的概览
print('df的概览:')
print(df.info())
print('\n')

# 显示头几行 默认显示五行
print(df.head(2))
print('\n')

# 显示后几行 默认显示后五行
print(df.tail(1))
print('\n')

# 获取DataFrame的列 
# 因为我们只获取一列,所以返回的是一个 Series
print(df['name'])
print(type(df['name']))
print('\n')

# 如果获取的是多个列,那返回的就是一个 DataFrame 类型:
print(df[['name','age']])
print(type(df[['name','age']]))
print('\n')

# 获取一行
print(df[0:1]) #左闭右开
print('\n')

# 取多行
print(df[1:3])
print('\n')

# 取多行里面的某一列(不能进行多行多列的选择)
# 注意 :df[]只能进行行选择,或列选择,不能同时多行多列选择 print(df[1:3]['name','age'])
print(df[1:3][['name','age']])
print('\n')
df_dict={
    'name':['James','Curry','Iversion'],
    'age':['18','20','19'],
    'national':['us','China','us']
}
df = pd.DataFrame(data=df_dict,index=['0','1','2'])
print(df)
print('\n')

# df.loc 通过标签索引行数据
# df.iloc 通过位置获取行数据

# 获取某一行某一列的数据
print(df.loc['0','name'])
print('\n')

# 一行所有列
print(df.loc['0',:])
print('\n')

# 某一行多列的数据
print(df.loc['0',['name','age']])
print('\n')

# 选择间隔的多行多列
print(df.loc[['0','2'],['name','national']])
print('\n')

# 选择连续的多行和间隔的多列
print(df.loc['0':'2',['name','national']])
print('\n')

# df.iloc 通过位置获取行数据 练习

# 取一行
print(df.iloc[1])
print('\n')

# 取连续多行
print(df.iloc[0:2]) #左闭右开
print('\n')

# 取间断的多行
print(df.iloc[[0,2],:])
print('\n')

# 取某一列
print(df.iloc[:,1].tolist())
print('\n')

# 按照坐标取某一个值
print(df.iloc[1,0])
print('\n')

# 修改值
df.iloc[0,0]='pandas'
print(df)

# DataFrame 中的排序方法
# ascending=False :降序排列 默认是升序
df = df.sort_values(by='age',ascending=False)
print(df)

DataFrame修改index columns

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

# dataframe 修改 行索引(index) 和 列索引(columns)

df1 = pd.DataFrame(np.arange(9).reshape(3,3),index=['bj','sh','gz'],columns= ['a','b','c'])
print(df1)

# 修改 df1 的索引
# df1.index = ['beijing','shanghai','guangzhou']
# print(df1)

# 自定义map函数(x 是原有的行列值)
def test_map(x):
    return x + '_ABC'

# inplace: 布尔值 ,默认为False 指定是否要返回新的DataFrame对象。如果为True,则在原df上进行修改
print(df1.rename(index=test_map,columns=test_map,inplace=False))
print(df1)

# 同时,rename 还可以传入字典,为某个 index 单独修改名称
df3 = df1.rename(index={'bj':'beijing'},columns={'a':'aa'})
print(df3)

# 列转化为索引
df1 = pd.DataFrame({'X':range(5),'Y':range(5),'S':list('abcde'),'Z':[1,1,2,2,2]})
print(df1)
print('\n')
# 指定一列为行索引(drop = False 指定同时保留作为索引的列)
result =  df1.set_index('S',drop=False)
result.index.name = None
print(result)
print('\n')

# 指定一行行转化为列索引
result =df1.set_axis(df1.iloc[0],axis=1,inplace=False)
result.columns.name = None
print(result)

添加及删除数据

# 添加元素
df1 = pd.DataFrame([['Snow','M',22],['Tyrion','M',22],['Snana','F',18],['Arya','F',14]],
                    columns=['name','gender','age'])
# 在数据最后再加上 score 一列
df1['score'] = [80,98,67,90] #增加列的元素个数要和原数据列的个数一样
print(df1)
print('\n')

col_name = df1.columns.tolist() # 将数据框中的列名全部提取出来放在列表里
col_name.insert(2,'city')
df1 = df1.reindex(columns=col_name)
print(df1)
print('\n')
# 给city列索引进行赋值
df1['city']=['北京','山西','湖北','澳门']
print(df1)

# df.insert(loc,column,value)
# lioc 要插入的位置 column 列名 value 值 前提:该列索引要不存在
# df1.insert(2,'score',[80,98,67,90])
# print(df1)
#  插入一行
df1 = pd.DataFrame([['Snow','M',22],['Tyrion','M',22],['Snana','F',18],['Arya','F',14]],
                    columns=['name','gender','age'])
print(df1)
print('\n')


# 先创建一个新的DataFrame对象,用来增加数据框的最后一行
new = pd.DataFrame({'name':'lisa',
                    'gender':'F',
                    'age':19
                   },index=[0])
print(new)
print('\n')
print('在原始数据df1最后一行新增一行,用append方法:')
# ignore_index=False表示不按原来的索引,从0开始自动递增
df1=df1.append(new,ignore_index=True)
print(df1)
# 合并对象
# ohjs:合并对象
# axis: 合并方式 ,默认0 表示按列进行合并,1表示按行合并
# ignore_index: 是否忽略索引

df1 = pd.DataFrame(np.arange(6).reshape(3,2),columns=['four','five'])
df2 = pd.DataFrame(np.arange(6).reshape(2,3),columns=['one','two','three'])
print('df1:')
print(df1)
print('df2:')
print(df2)

# 按行合并
result = pd.concat([df1,df2],axis=1)
print(result)

# 按列合并
result = pd.concat([df1,df2],axis=0,ignore_index=True)
print(result)
# DataFrame的删除
# labels:要删除数据的标签
# axis: 0表示删除行,1表示删除列,默认0
# inplace: 是否在当前df中执行此操作

df2 = pd.DataFrame(np.arange(9).reshape(3,3),columns=['one','two','three'])
print(df2)
df3 = df2.drop(['one'],axis=1,inplace = False)
print(df3)
print(df2)

数据处理

# 数组处理
from numpy import nan as NaN

# 通过 ** dropna() ** 过滤缺失数据
se = pd.Series([4,NaN,8,NaN,5])
print(se.tolist())
# 去掉无意义的值(NaN)
print(se.dropna().tolist())
print(se.notnull().tolist())
print(se.isnull().tolist())

# 通过 布尔序列 也能进行滤除
print(se[se.notnull()].tolist())
# 二维数组的过滤
df1 = pd.DataFrame([[1,2,3],[NaN,NaN,2],[NaN,NaN,NaN],[8,8,NaN]])
print(df1)
print('\n')

# 默认消除所有包含 NaN 的列或行:
print(df1.dropna())
print('\n')

# 传入 how = 'all' 滤除全为 NaN 的行
print(df1.dropna(how = 'all')) #默认情况下是 any ,只要有 nan 就删除
print('\n')


# 传入 axis = 1 滤除列
print(df1.dropna(axis=1,how='all'))
print('\n')

# 传入 thresh = n 保留至少有 n 个非 NaN 数据的 行:
print(df1.dropna(thresh=1))
# 填充缺失数据
df1 = pd.DataFrame([[1,2,3],[NaN,NaN,2],[NaN,NaN,NaN],[8,8,NaN]])
print(df1)
print('\n')

# 用常数填充 fillna
print(df1.fillna(0))
print('\n')
# 传入 inplace = True 直接修改 原对象
# df1.fillna(0,inplace = True)
# print(df1)

# 通过字典填充不同的常数 这里的0,1,2 表示列索引
print(df1.fillna({0:10,1:20,2:30}))
print('\n')

# 填充平均值
print(df1.fillna(df1.mean()))
print('\n')

# 如果只填充一列
print(df1.iloc[:,1].fillna(5,inplace = True))
print(df1)
print('\n')
# 传入 mothod = '' 改变插值方式:

df2 = pd.DataFrame(np.random.randint(0, 10, (5, 5)))
print(df2)
print('\n')
df2.iloc[1:4, 3] = np.nan
df2.iloc[2:4, 4] = np.nan
print(df2)
print('\n')

# 使用  (行)上面的值来填充 ffill  用后面的值来填充 bfill
print(df2.fillna(method='ffill'))
print('\n')

# 使用 limit= '' 限制填充行数:
print(df2.fillna(method='ffill', limit=1))
print('\n')
# axis 控制方向 1 表示列 这里是只填充一列 ,使用左边的值进行填充
print(df2.fillna(method='ffill', limit=1, axis=1))
# 移除重复数据
# dataframe 中经常会出现重复行,利用 duplicated() 函数 返回每一行判断是否重复的结果
# 重复为 True

df1 = pd.DataFrame({'A': [1, 1, 1, 2, 2, 3, 1], 'B': list('aabbbca')})
print(df1)
print('\n')

# 判断每一行是否重复(结果是 bool值,TRUE 代表重复的)
print(df1.duplicated().tolist())
print('\n')

# 去除全部的重复行
print(df1.drop_duplicates())
print('\n')

# 指定列去除重复行
print(df1.drop_duplicates(['A']))
print('\n')

# 保留重复行中的最后一行
print(df1.drop_duplicates(['A'], keep='last'))
print('\n')

# 去除重复的同时改变DataFrame对象
df1.drop_duplicates(['A', 'B'], inplace=True)
print(df1)

数据合并

# 数据合并

# 使用 join 合并 着重关注的是行的合并

import pandas as pd

df3 = pd.DataFrame({'Red':[1,3,5],'Green':[5,0,3]},index=list('abc'))
df4 = pd.DataFrame({'Blue':[1,9,8],'Yellow':[6,6,7]},index=list('cde'))
print(df3)
print(df4)

# 简单合并(默认是left 左连接,以左侧 dfs 为例)
# 左连接
# df3.join(df4,how='left')
# 右连接
# df3.join(df4,how='right')
# 外连接
# df3.join(df4,how='outer')

# 合并多个DataFrame对象 
df5 = pd.DataFrame({'Brown':[3,4,5],'White':[1,1,2]},index=list('aed'))
df3.join([df4,df5])
# 使用merge,看重的是列合并
df1 = pd.DataFrame({'名字': list('ABCDE'), '性别': ['男', '女', '男', '男', '女'], '职称':
                    ['副教授', '讲师', '助教', '教授', '助教']}, index=range(1001, 1006))
df1.columns.name = '学院老师'
df1.index.name = '编号'
print(df1)
print('\n')

df2 = pd.DataFrame({'名字': list('ABDAX'), '课程': ['C++', '计算机导论', '汇编', '数据结构', '马克思原理'], '职称':
                    ['副教授', '讲师', '教授', '副教授', '讲师']}, index=range(1001, 1006))
df2.columns.name = '课程'
df1.index.name = '编号'
print(df2)
print('\n')

# 默认下是根据左右对象中出现同名的列作为连接的键,且连接方式是 how = 'inner'
print(pd.merge(df1,df2)) #返回匹配的
print('\n')

# 指定列名合并
# pd.merge(df1,df2,on='名字',suffixes=['_1','_2']) # 返回匹配的

# 连接方式,根据左侧为准
pd.merge(df1,df2,how='left')

# 根据右侧为准
pd.merge(df1,df2,how='right')

# 所有
pd.merge(df1,df2,how='outer')

# 根据多个键进行连接
pd.merge(df1,df2,on=['职称','名字'])

多层索引(扩展)

# 多级索引
# Series
s = Series(np.random.randint(0, 150, size=6), index=[['a', 'a', 'b', 'b', 'c', 'c'],
                                                     ['期中', '期末', '期中', '期末', '期中', '期末']])
print(s)
print('\n')

# 取一个第一级索引
print(s['a'])
print('\n')

# 取多个第一级索引
print(s[['a','b']])
print('\n')

# 根据索引获取值
print(s['a','期末'])
print('\n')

# loc 方法取值
print(s.loc['a'])
print(s.loc[['a','b']])
print(s.loc['a','期末'])
print('\n')

# iloc 方法取值(iloc 计算的是最内层索引)
print(s.iloc[1])
print(s.iloc[1:4])

时间序列

# 时间序列
import pandas as pd 
import numpy as np

# 生成一段时间范围
data = pd.date_range(start='20190501',end='20190530')
print(data)

# freg: 日期偏移量 取值为 string 或 DateOffset,默认为'D', freg='1h30min'
# freg ='10D'
# periods;固定时期,取值为整数或None 就是生成几个数据

date = pd.date_range(start='20190501',periods=10,freq='10D')
print(date)
# 时间序列在series中的作用
# 可以将时间作为索引
index = pd.date_range(start='20190101', periods=10)
df = pd.Series(np.random.randint(0,10,size=10),index=index)
print(df)

# truncate 这个函数 根据日期过滤 before 之后的日期  after :之前的日期
after = df.truncate(after='2019-01-2')
print(after) 
# 日期的一些常见属性
long_ts = pd.Series(np.random.randn(
    1000), index=pd.date_range('1/1/2019', periods=1000))
print(long_ts)
print('\n')

# 根据年份获取 
# result = long_ts['2020']
# print(result)
# print('\n')

# 根据年份和日期获取
# result = long_ts['2020-05']
# print(result)

# 使用切片
# result = long_ts['2020-05-01':'2020-05-06']
# print(result)

# 通过between_time()返回指定时间段的数据集
index = pd.date_range('2018-03-17', '2018-03-30', freq='2H')
ts = pd.Series(np.random.randn(157), index=index)
print(ts.between_time('7:00', '17:00'))
print('\n')

# 这些操作也适用于dataframe
index = pd.date_range('1/1/2019',periods=100)
df =  pd.DataFrame(np.random.rand(100,4),index=index)
print(df.loc['2019-04'])

分组聚合(常用)

# 分组聚合

df = pd.DataFrame({
    'name': ['BOSS', 'Lilei', 'Lilei', 'Han', 'BOSS', 'BOSS', 'Han', 'BOSS'],
    'Year': [2016, 2016, 2016, 2016, 2017, 2017, 2017, 2017],
    'Salary': [999999, 20000, 25000, 3000, 9999999, 999999, 3500, 999999],
    'Bonus': [100000, 20000, 20000, 5000, 200000, 300000, 3000, 400000]
})
print(df)

# 根据name 这一列进行分组
group_by_name = df.groupby('name')
print(type(group_by_name))
# 查看分组
print('\n')
print(group_by_name.groups)
print('\n')
# 分组后的数量
print(group_by_name.count())
print('\n')

# 查看分组的情况
for name,group in group_by_name:
    print(name)  # 组的名字
    print(group) # 组具体内容

print('\n')
# 可以选择分组
print(group_by_name.get_group('BOSS'))
print('\n')

# 按照某一列进行分组 ,将name 这一列作为分组的键,对year 进行分组
group_by_name = df['Year'].groupby(df['name'])
print(group_by_name.count())
print('\n')

# 按照多列进行分组
group_by_name_year = df.groupby(['name','Year'])
print('分组数量:')
print(group_by_name_year.count())
print('按照多列进行分组:')
for name,group in group_by_name_year:
    print(name)
    print(group)
    
print('\n')
    
# 可以选择分组
print(group_by_name_year.get_group(('BOSS',2016)))
# '''
# 聚合函数
# mean   计算分组平均值
# count  分组中非NA值的数量
# sum    非NA值的和
# median 非NA值的算术中位数
# std    标准差
# var    方差
# min    非NA值的最小值
# max    非NA值的最大值
# prod   非NA值的积
# first  第一个非NA值
# last   最后一个非NA值
# mad	   平均绝对偏差
# mode	模
# abs	    绝对值
# sem	平均值的标准误差
# skew	样品偏斜度(三阶矩)
# kurt	样品峰度(四阶矩)
# quantile	样本分位数(百分位上的值)
# cumsum	累积总和
# cumprod	累积乘积
# cummax	累积最大值
# cummin	累积最小值
# '''# '''
# 聚合函数
# mean   计算分组平均值
# count  分组中非NA值的数量
# sum    非NA值的和
# median 非NA值的算术中位数
# std    标准差
# var    方差
# min    非NA值的最小值
# max    非NA值的最大值
# prod   非NA值的积
# first  第一个非NA值
# last   最后一个非NA值
# mad	   平均绝对偏差
# mode	模
# abs	    绝对值
# sem	平均值的标准误差
# skew	样品偏斜度(三阶矩)
# kurt	样品峰度(四阶矩)
# quantile	样本分位数(百分位上的值)
# cumsum	累积总和
# cumprod	累积乘积
# cummax	累积最大值
# cummin	累积最小值
# '''
# 使用 agg()函数做聚合运算 通用 通过参数传参
for name,group in df1.groupby('key1'):
    print(name)
    print(group)
print('\n')    
print(df1.groupby('key1').agg('sum'))
# 优势在于可以同时做多个聚合运算
print(df1.groupby('key1').agg(['sum','mean','std']))

# agg()还可以传入自定义函数 
def peak_range(df):
    return df.max()-df.min()
print(df1.groupby('key1').agg(peak_range))

print('\n')
print('同时应用多个聚合函数:')
# 同时应用多个聚合函数
print(df1.groupby('key1').agg(['mean','std','count',peak_range]))
print('\n')
# 通过元组提供新的列名 就是别名
print(df1.groupby('key1').agg(['mean','std','count',('range',peak_range)]))
print('\n')

print('给每列作用不同的函数:')
# 给每列作用不同的函数
dict_mapping = {
    'Data1':['mean','max'],
    'Data2':'sum'
}
print(df1.groupby('key1').agg(dict_mapping))
# apply() 函数 : pandas 中自由度最高的函数
# agg() 函数 只是用来数值计算,一些非数值会被过滤,存在缺陷

df1 = pd.DataFrame(
    {
        'sex': list('FFMFMMF'),
        'smoker': list('YNYYNYY'),
        'age': [21, 30, 17, 37, 40, 18, 26],
        'weight': [120, 100, 132, 140, 94, 89, 123]
    }
)

print(df1)
print('\n')

# 判断抽烟年龄


def bin_age(age):
    if age >= 18:
        return '早日戒烟'
    else:
        return '很好啊啊'


print(df1['age'].apply(bin_age))
# df1['age']=df1['age'].apply(bin_age)
# print(df1)


# 取出抽烟和不抽烟的体重的前二
def top(smoker,col,n=5):
    return smoker.sort_values(by=col)[-n:]

df1.groupby('smoker').apply(top,col='weight',n=2)
posted @ 2021-01-23 23:39  一粒盐  阅读(1135)  评论(0编辑  收藏  举报