【学习】pandas总结

https://github.com/datawhalechina/joyful-pandas

基于自己的日常工作,整理必备的一些知识点,覆盖95%+的使用场景。

第一章 基础

1.1 文件读取与写入

df = pd.read_csv('data/table.csv')
df_excel = pd.read_excel('data/table.xlsx')
df.to_csv('data/new_table.csv')
df.to_excel('data/new_table2.xlsx', sheet_name='Sheet1')

1.2 基本数据结构

Series

  • 查看Series自带的额方法


    image.png

Dataframe

  • 新增列的方法
    常规方法
df['B']=list('abc')
df.assign(B=pd.Series(list('abc)))
df.merge(pd.Dataframe({'B':['abc']}, how='left', left_index=True, right_index=True))

一般用的都是第一种和第三种方法,实际上第二种方法和第三种方法是等效的,都是讲究索引对齐性(left_jone,index),在索引未严格对其的情况下就是缺失值。用第二种方法其实更简便,但用三种方法更普遍。。

转换

s.to_frame()
s.to_fame().T

1.3 常用基本函数

df.head()
df.tail()
df.unique()
df.nunique()
df.count()   #各列的非空值个数
df.value_counts()
df.info()
df.describe()
df.describe(percentiles=[.05, .25, .75, .95])  # 可以自行选择分位数
df['Math'].idxmax()
df['Math'].nlargest(3)

如果要返回最大几个值的index,可以用nlargest再返回index,也可以sort_values再返回index。和numpy里面的np.argsort()可以起到一样的效果

df['Math'].clip(33,80)  #截断,最小值和最大值进行限制
df.replace({'Address':{'street_1':'one','street_2':'two'}}) #字典替换,这里是限定支队Address列进行替换 
df.apply(lambda x : x.apply(lambda x:str(x)+'new'))   #单列apply和全局apply的应用,相当于applymap

1.4 排序

df.sort_index()
df.sort_values()

第二章 索引

2.1 单级索引

  • loc
    包括单列/行,多列/行,行列联合,函数索引和布尔索引(函数索引和布尔索引本质上无区别)
df.loc[:,'Height':'Math'] #这样的多列索引也是可以的
df.loc[[True if i[-1]=='4' or i[-1]=='7' else False for i in df['Address'].values]].head() #这样的布尔索引可能略绕,不如直接把需要提取的index提取出来
  • iloc
  • []操作符
    严格来说,[]索引只适合布尔索引和列索引,对行索引要用loc和iloc,不然很容易造成困扰。
df[df>80]
df['math']
  • 布尔索引

广泛使用的布尔符号:&, |, ~, isin

df[(df['Gender']=='F')&(df['Address']=='street_2')].head()
  • 快速标量索引


    【学习】pandas总结_第1张图片
    image.png

    看需求使用吧,在数据量大的时候特别需要用到

  • 区间索引

  • interval_range可以创造区间(注意调节左右开闭性)


    【学习】pandas总结_第2张图片
    image.png
  • pd.cut可以将数值进行区间统计


    【学习】pandas总结_第3张图片
    image.png

    当然也而已利用interval_range确定区间,而不是自己输入bins

df['bins'] = pd.cut(df['math'],pd.interval_range(start=0,end=100,freq=20,closed='left'))
  • 区间索引
df.set_index('bins').loc[[30,50]] #只要区间和30、50有交叉就会被选中

区间索引虽然用得少,但是一旦需要用的时候如果掌握不好就很麻烦。总的来说,pd.interval_range基本只在生成df的时候使用,对已有的数据,一般采用pd.cut和loc的方法来进行索引!!

2.2 多级索引

  • 创建多级索引的方式

tuple\array等等都可以,掌握两种就可以了

from_tuples(虽然是from_tuples,但其实tuples,arrays都可以自动转换)

arrays = [['A','a'],['A','b'],['B','a'],['B','b']]
mul_index = pd.MultiIndex.from_tuples(arrays, names=('Upper', 'Lower'))
pd.DataFrame({'Score':['perfect','good','fair','bad']},index=mul_index)

names不是必须的,看自己需要,我觉得没啥实际意义。。

from_product(from_tuples是完全匹配,from_product是两两相乘的方式)

【学习】pandas总结_第4张图片
image.png

  • 切片索引
display(df.loc[[('A','a'),('B','a')]])
display(df.loc[['A','B']])
df.loc[[('A'),('B','a')]] #会报错,所以对mul_index必须统一level进行loc索引

差不多可以知道对mul_index进行loc索引很复杂,要不然就用布尔索引,要不然就转换成单一index后进行索引。。

2.3 索引设定

  • reindex\reset_index\set_index
    reindex相当于loc的功能,原始没有的index可以选择填充(默认为空值填充)
    reset_index会将当前index生成为新的一列
    set_index删除当前index并将另一列设置为index,利用append参数可以将当前索引维持不变
【学习】pandas总结_第5张图片
image.png

set_index是最灵活的,可以覆盖reindex的功能

  • rename_axis和rename
    rename_axis是修改index名和columns名,rename是修改里面的label。。。而且rename_axis有点绕,理论上index_name和columns_name都没有存在的必要,所以这种情况下用rename来直接修改label就可以了。对于mul_index的情况
arrays = [['A','a'],['A','b'],['B','a'],['B','b']]
mul_index = pd.MultiIndex.from_tuples(arrays, names=('Upper', 'Lower'))
df = pd.DataFrame({'Score':['perfect','good','fair','bad']},index=mul_index)

df.rename_axis(index=['A','B'])   #可以
df.rename_axis(index={'Upper':'A','Lower':'B'})  #可以
df.rename_axis({'Upper':'A','Lower':'B'},aixs=0)   #不可以
df.rename_axis(['A','B'],axis=0) #可以

所以不是mul_index基本都不会用到

2.4 索引型函数

  • where和mask
    where类似于布尔索引,但布尔索引是只显示符合条件的行列,where是显示全部行列,而不符合的行全部显示为空值


    【学习】pandas总结_第6张图片
    image.png

    mask则是符合的行全部显示为空值

2.5 重复项处理

  • duplicated和drop_duplicates
    duplicated返回布尔Series,drop_duplicates保留经过删除重复项之后的行。
    可以自行设置是以某一列去除重复行还是以全部列去除重复行。

2.5 抽样

df.sample(n=5) #随机抽样5行
df.sample(n=5,axis=1) #随机抽样5列
df.sample(frac=0.5) #随机比例抽样
df.sample(n=5,inplace=True) #有放回抽样
df.sample(n=5, weights = df['math'])  #设置权重,这里是以某一列的数值为权重来决定该行被抽中的概率,自动归一化

第三章 分组

3.2 groupby

  • 分组
df_grouped = df.groupby('col') #以某列分组可以,每个组的Dataframe的index仍然是原始的index,而不是col
df_grouped = df.groupby(level=0) #以index进行分组,level都是针对index而言的,一个单索引的level只能等于0!!
df_grouped =  df.set_index('col').groupby('col') #也是以index进行分组,不过这个时候不等同于df.groupby('col'),每个组的Dataframe的index是col
【学习】pandas总结_第7张图片
image.png

实际上分组的方式特别灵活,可以参见下面的连续性变量分组

  • 组的容量和组数
df_grouped.size() #各个组的行数
df_grouped.ngroups #组的数目
df_grouped.groups #各个组的详情
df_grouped.get_group('a') # 获取特定组,dataframe格式

其实size是最方便的,相当于value_counts的功能,能够直接简单的知道有多少分组

  • 组的遍历
for name,group in df_grouped:
    print(name)
    display(group)
  • 连续型变量分组


    【学习】pandas总结_第8张图片
    image.png

    也可以先加入一列interval_range后以该列进行分组


    【学习】pandas总结_第9张图片
    image.png

3.3 SAC

统一讲一下agg,transform,apply的区别

  • 在不做groupby的情况下,没有agg的事。。。然后transform和apply本质上无区别,都是对列进行运算,但是不是聚合运算
  • 在做了groupby的情况下,agg内置函数最快,transform针对非groupby列进行聚合运算,apply针对包括groupby列进行聚合运算。。当然如果限定了对某列进行运算的话,transform和apply无本质区别。。


    【学习】pandas总结_第10张图片
    image.png
  • 还有就是applymap是针对所有值进行运算。

总结:在内置函数聚合运算的时候用agg,其他时候用apply是基本完全可以替代transform的,transform和apply只有一点是否要对groupby列进行聚合运算的差异。

第四章 变形

4.1 透视表

  • pivot_table
    透视的核心四要素是:index(行)、columns(列)、value(值)和运算方式(aggfunc),如果不选aggfunc就是默认mean
pd.pivot_table(df,index='School',columns='Gender',values='Height',aggfunc=['mean','sum'],margins=True).head()

margin可以汇总状态,相当于不再细分value。。


【学习】pandas总结_第11张图片
image.png

如果是要计数的话,必须选定一列,然后进行count:

pd.pivot(df, index=A,columns=B,values=‘C’,aggfunc=['count'])
  • crosstab
    貌似属于简化版的pivot_table,不支持多级index和多级columns

4.3 stack 和 unstack

  • stack
    stack是把原来的列作为行进行展开
df.stack(0)  #如果是mul_col,则将最外层列展开为行,
df.stack(1) #至少得是mul_col才能展开 
  • unstack
    stack的逆函数,把行变为列,实际上就是pivot_tabel

4.3 dummy

pd.get_dummies(df)

one-hot编码

第五章 合并

5.1 append 和 assign

  • append
    按序列添加行,和pd.concat axis=0功能一样,但是这个要求是按序列进行拼接,pd.concat 并不会去检查序列,好像是顺序匹配

  • assign
    按序列添加列,和pd.concat axis=1功能一样,同理也是要求按序列拼接

5.2 combine 和 update

combine是按条件用一个新的df去更新原df的列值,update是不管条件用新的df去覆盖原df的列值。。但是两者的应用场景应该是比较少,不如直接用apply的方式比较通用。

5.3 concat

最常用的拼接之一

5.4 merge和join

merge自然是最常用的拼接(之二),join和merge似乎没有区别,只是默认的连接方式不一致罢了。

第六章 缺失数据

6.1 缺失类型

  • isnull 和 notnull来确定缺失值
df.isnull().sum()
df.isnull().all()
df.isnull().any()

all()是所有值都是True值(设定axis)才会返回True,any()是只要有一个是True就会返回True.
涉及到什么值是True,基本上,只有0、''、False才是False,其余都是True,包括np.nan值。。None值也是True。。所以为了避免误区,建议只针对bool值用any和all

  • 其余缺失符号
    np.nan None 和NaT(时间的nan)
    基本上没有太大必要去单独掌握。。

  • 所有类型
    重点说一下,目前包括的类型为:
  1. float
  2. int
  3. bool
  4. datetime64[ns]
  5. datetime64[ns, tz]
  6. timedelta[ns]
  7. category
  8. object
    默认的数据类型是int64,float64,object和str也是等价,会自动转换为object

6.2 缺失值的运算

基本上针对缺失值基本就是直接略过处理


【学习】pandas总结_第12张图片
image.png

6.3 填充与剔除

  • 填充
df.fillna('value')
df.fillna(method='ffill')
df.fillna(method='backfill')
df.fillna(df.mean()) #自动对齐特性
  • 剔除
df.dropna(axis=1)   #默认就是部分缺失则去除
df.dropna(axis=0)  #默认就是部分缺失则去除
df.dropna(axis=1,how='all') #全缺失去除
df.dropna(axis=1,how='any') #部分缺失去除
df.dropna(axis=0,subset=['B','C']) #对特定列进行缺失搜索

6.4 插值

  • 线性插值
# s是series
s.interpolate() # 与index无关的插值,只考虑index的顺序而不是值
s.interpolate(method='index') # 与index有关的插值,需要考虑idnex的值
s.interpolate(method='time')  #与index有关,并且index是时间格式
  • 高级插值
    多项式差值、样条插值等等。。也是可以通过设定method实现

第七章 文本数据

7.2 拆分与拼接

  • 拆分split
s = pd.Series(['a_b_c', 'c_d_e', np.nan, 'f_g_h'], dtype="str")
s.str.split('_')  #拆分后成为list
s.str.split('_').str[0] # 列表的第0项
s.str[0] #str的第0项
s.str.split('_',expand=True,n=1) #expand控制是否需要展开为多列,n控制展开的列数

str的相关方法都是针对series(或者index的list)操作

  • 拼接cat
s = pd.Series(['ab',None,'d'],dtype='string')
s.str.cat(sep=',',na_rep='*') #sep控制拼接符、na_rep控制对缺失值的替代处理

str.cat只能对series操作,拼接之后是一个str


image.png
s.str.cat(s2,sep=',',na_rep='*') #两个series合并,则按序列进行拼接,默认left_join
s.str.cat([s+'0',s*2]) #也可以进行series和df/多个series的拼接
s.str.cat(df) #也可以进行series和df/多个series的拼接

如果要对df的所有列进行拼接,可以采用以下方法

df.iloc[:,0].str.cat(df.iloc[:,1:]) #必须以series作为引导

4.3 替换

  • replace
    支持正则匹配替换,用r开头
s.str.replace(r'^[AB]','***')
s.str.replace(r'([ABC])(\w+)',lambda x:x.group(2)[1:]+'*') #允许匿名进行group的操作,0返回字符本身,从1开始才是子组
s.str.replace(r'(?P[ABC])(?P\w+)',lambda x:x.group('two')[1:]+'*') #利用?P<....>表达式可以对子组命名调用

df的replace是全局替换(好像如果采用regex参数也可以实现正则匹配),str.replace是允许正则匹配的

4.4 子串匹配与提取

  • str.extract
    str.extract是综合split和replace的功能,实现更加灵活的匹配
#下面两种情况结果是一样的
pd.Series(['10-87', '10-88', '10-89'],dtype="string").str.extract(r'([\d]{2})-([\d]{2})')
pd.Series(['10-87', '10-88', '10-89'],dtype="string").str.split('_', expand=True)

replace只能返回某一个group的值,extract能把所有符合要求的group都返回,以及实现拆分

  • str.extractall
    会全匹配,如果可以匹配多个结果,则建立多级索引

  • str.contains
    同样支持正则匹配

pd.Series(['1', None, '3a', '3b', '03c'], dtype="string").str.contains(r'[0-9][a-z]')
  • str.match
    str.match与其区别在于,match依赖于python的re.match,检测内容为是否从头开始包含该正则模式

4.3 其他常用方法

  • str.strip
  • str.lower和str.upper
  • str.swapcase和str.capitalize
    分别表示交换字母大小写和大写首字母
  • str.isnumeric()
    判断是否是数值

第八章

整体来说分类category应该用到得很少

pd.Categorical(["a", "b", "c", "a"], categories=['a','b','c']) #这是类似于list的categrical数据
s = pd.Series(cat) #这是dtype为category的series
image.png

这个就是catgorical数据,形似list
一些最基本的方法

s.cat.categories #查看分类情况
s.cat.ordered #查看是否排序,虽然一般用不到

还有一些修改categories的方法,一般用不到,如果需要用的时候,可以用pd.cut或者pd.Categorical来生成新列

你可能感兴趣的:(【学习】pandas总结)