Pandas 索引对齐、缺失值

开篇

当在进行Series、DataFrame这两个对象的二元运算时,有稍不同于Numpy的处理方式。

本篇将以组合不同来源的数据为起点,探究其中发生的索引对齐,过程中产生的缺失值的特性和处理手段,以及更进一步的数据集合并方法。

引子——Pandas的NumPy-based特性

因为Pandas是建立在NumPy的基础之上的,所以NumPy的通用函数仍适用于Series对象和DataFrame对象。你可以在NumPy的通用函数里传入一个Series对象,会返回一个保留索引的Pandas对象。*下面代码中的randomstate是随机数种子的意思

import numpy as np
import pandas as pd

ser=pd.Series(np.random.RandomState(42).randint(0,10,4))#ndarray可以用来创建Series
print(np.exp(ser))#Series可以传入NumPy的方法

一、索引对齐与集合运算规则

1.1 两个Series,index的并集

简言之,对两个不同的Series进行二元运算得到的新的Series对象的index将是原来两个的Series的并集。

import pandas as pd

score_math = pd.Series({'小明':58,'小丁':79,'小红':84,'小华':98})
score_English = pd.Series({'小陈':72,'小卡':100,'小红':84,'小明':89})

print(score_math+score_English)
#只要不是共有的index对应的数值一定是NaN

 很多NaN,很难受,这也和NaN本身的特性有关系,稍后会提到。

1.2  两个DataFrame,类似的并集

在介绍DataFrame的对齐之前,需要先入为主的是——DataFrame很贴心,我哭死。

1.2.1 一个之后会用到的构造函数来减少我的书写量

import pandas as pd
def make_df(cols,ind):
    data=pd.DataFrame({c:[str(c)+str(i) for i in ind] for c in cols})
    return data


#易读版
import pandas as pd
def make_df_easy(cols,ind):
    datadict={}
    datalist=[]
    for c in cols:
        for i in ind: 
            datalist.append(str(c)+str(i))
        datadict[c]=datalist
        datalist=[]
    data=pd.DataFrame(datadict)
    return data


以下是测试语句,可以拿去试试
df1=make_df_easy('ABC',[1,2,3])
print('df1是\n',df1)


df2=make_df('DEF',[1,2,3])
print('df2是\n',df2)

1.2.2 如果这两个DataFrame的列名(columns)完全相同(顺序无所谓),对应index个数也相等(说到底就是形状一样)

df1=make_df('ABC',[1,2,3])
df2=make_df('CAB',[6,7,8])

print(df1+df2)

1.2.3 只要形状不一样,不一样的地方就是NaN

df1=make_df('ABC',[1,2,3])

df2=make_df('CA',[6,7])

df3=make_df('CAE',[5,6,7])

print(df1+df2)
print(df1+df3)

在第一个print中,列会取并集得到A、B、C,三列,但是B列是不会有值的,且由于df2只有两行 ,就算df1有三行,第三行也将全是NaN。

有一点木桶效应的意思在里面,虽然最后得到的形状是向外兼容最大的并集,但实际有效的数据是交出来的,在第一个print里体现为,会有ABC三列,每列三行,但只有AC两列中的两行是有效的,在第二个print中体现为,会有ABCE四列,每列三行,但只有AC两列的三行是有效的

1.3 一个Series和一个DataFrame呢? 

如果我们回想NumPy中的广播,比如拿一个二维数组(shape=(3,4)),减一个长度为4的一维数组,结果会体现成每一行分别对应减去了这个一维数组里的值(如第一行第一个减一维数组中第一个,第二个减第二个……第二行第一个减一维中第一个……)

一个DataFrame和一个Series做运算,也是按行来的。需要注意的是,Series的index在进行索引对齐的时候(因为默认是一行一行的),index会与DataFrame的column对齐  

import pandas as pd
import numpy as np
df=pd.DataFrame(np.arange(12).reshape((3,4)),columns=list('QRST'))
ser=pd.Series([13,5,18,65],index=list('QRST'))
print(df)
print(df-ser)

你是不能直接的用算术运算符来做出列运算的效果

1.4 但你可以用正儿八经的通用函数

Python运算符与Pandas方法的映射关系
Python运算符Pandas方法
+                加法add ( )

-                减法

sub( )   subtract()
*                乘法mul() multiply()
/                除法truediv() div() divide()
//                地板除floordiv()
%                取余mod()
**                乘方pow()

只需要指定轴就可以了👇,注意Series的长度就行

import pandas as pd
import numpy as np
df=pd.DataFrame(np.arange(12).reshape((3,4)),columns=list('QRST'))
ser=pd.Series([13,5,18])
print(df)
print(df.subtract(ser,axis=0))

你也可以利用DataFrame自身的行与列

比如
如果是行还是直接减就可以了
df-df[0]

列的话↓
df.subtract(df['R'],axis=0)#减去R列的值

通用函数不止是可以针对轴,也可以对缺失值作出处理,也可以决定索引对齐的层级。

第一部分只是让你对并集是个啥有个大概的概念,以及得到一些缺失值

二、我们关注缺失值

Pandas选择的是标签方法来表示缺失值,包括两种原有的Pythono缺失值:浮点数据类型的NaN值(也是数值类型的缺失值)和None对象(Python对象类型的缺失值)。由于本文的入门性,就不在这里阐释None

当一个数组包含None的时候,如果你对这个数组进行累计操作,比如求和,求最值这样的聚合函数,通常会出现TypeError——Python是没定义None和一些数据的计算的(比如整数)

2.1 NaN,数值病毒(更像是传染孢子)

无论你的数据和NaN进行何种操作,结果都将是NaN    : ),不会抛出异常,但结果都是NaN

import numpy as np
print(1+np.nan)
print(0*np.nan)
print(np.array([1,np.nan,2,48]).sum())
print(np.array([1,np.nan,2,48]).max())

2.2 如何处理缺失值——发现,剔除,替换

2.2.(0.5) 可以忽略缺失值的方法(numpy里的)

np.nansum() , np.nanmin(), np.nanmax()_可以套到2.1中的代码块里来看

2.2.1 快把它弄出来,快把它弄出来!

两个有效的方法发现缺失值—— isnull( ) 和 notnull( ),返回一个布尔数组,你可以从True和False里再结合函数名判断它是不是缺失值。

然后根据DataFrame的NumPy-based的特点,我们其实可以通过传入这个布尔数组来对空值或者非空值进行索引,在前面提到的链接中你也能看到这一部分的内容。

这样的索引一般在Series里才有点作用。(Series[Series.notnull ( ) ])

2.2.2 滚出加基森(可以填补什么,可以怎么填补)

剔除有两种形式,删掉和补上。dropna() 和 fillna()

对于一维的Series直接用就行了,dropna()会直接抹除Series中的缺失值,而在fillna()中,你可以设置:

传入的值和填补的方式

你可以传入什么?单一的标量,缺失值位置前后的值,一些特定的量(比如平均数),一个字典,字典的键决定你要填补的列,然后字典键对应的值则用来填充那一列所有缺失值

注意你要传入的字典是单纯的字典,那个字典的键只能对应一个值

不要妄想让一个列表字典去个性化的填充缺失值(你可能想着如果这一列有两个缺失值,那我一个字典,键对应一个两个元素的列表依次填进去)但这行不通。

下面的代码介绍的是method参数

import pandas as pd
data=pd.Series([1,np.nan,2,None,3,5],index=list('abcdef'))

print(data.fillna(0))

print(data.fillna(method='ffill'))

method有几个可取值 backfill bfill>>>用后一个非缺失值去填充该缺失值
ffill/pad>>>用前一个非缺失值去填充该缺失值

在用这种“位置方法”,如果一个缺失值的相应位置没有可以拿来填的数字,那么它继续成为NaN

·  你可以指定最多几个被fill >> limit参数—— 一个整数,决定了你最多填补几个

·  你可以指定对原数组删补还是返回一个新数组 >> inplace参数,默认false,函数会返回一个新的被删补的pandas对象,设置为True则对原数组进行删补,返回值是空(None),意思是你试图把一个inplace=True的这个方法的返回值传入并打印新变量是无意义的。 

2.2.3 DataFrame 更多的要求

对于DataFrame来说,由于是二维,删除和填充的时候需要设置坐标轴。当然想要达到某种填充效果还是可以用method参数。由于是二维,删除单个的缺失值是没有意义的,你删除了他还相当于是缺失,因此只能剔除NaN所在的一整行或者一整列

你当然会注意到这样也会把非缺失值给去掉,因此我们可以通过调整dropna()的参数来调整

how参数:如果是 'all',则只有这一行/列全为缺失它才会被删除,如果是"any",则只要有缺失值它就会被删除

tresh参数:设置非缺失值的最小数量MIN。如果在某列/行中,非缺失值的个数比MIN还小了,那他就肯定会被删掉了。

下一次将讨论数据集合并与分组

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值