Python学习笔记(6-2):若干细节知识

在这里插入图片描述

文章导读

 - 课程难度:★★☆☆☆
 - 预计学习时间:30分钟
 - 简介:本节主要讲解了运用python进行数据分析时,常见异常值的特点及检验方法,包括:(1)几种空值和异常值的特点,及其获取和检测的方法;(2)if x和bool(x)的计算机制及返回值问题;(3)is判别原理及元素的内存地址ID问题;
 - 重点涉及的函数和内容:(1)利用a==a的判别方式检测一个值是否为nan值;(2)`==` 比较的是两个变量的值,而`is`实际上比较的是两个元素的内存地址。

一、 几种空值和异常值的特性

1、None值

它的数据类型是NoneType,是一个“什么都没有”的标识符,不是0,也不是空字符串。它的特性如下:
(1)None不能进行算术运算:

2 * None	# 报错1
【报错1】TypeError: unsupported operand type(s) for *: 'int' and 'NoneType'

(2)判别:用等于号“==”或is关键字来做是否等于的判别,不能做大小比较

print(None == None)
print(None is None)
print(None != 2)
print(None > None) 		# 报错1
print(None > 2) 		# 报错2

输出结果如下:

True
True
True
# 报错1【TypeError: '>' not supported between instances of 'NoneType' and 'NoneType'】
# 报错2【TypeError: '>' not supported between instances of 'NoneType' and 'int'】

None一般是我们初始化的时候,将某个会在在程序的执行过程中被更改的变量初始化为None。之后,在某个地方观察这个变量是否从None改成了其他值,执行对应的处理。

2、无穷大

无穷大的数据类型为浮点型,即:float

(1)初始化

初始化一个无穷大的值有三种方式。一是设置一个很大的常数,常数设置地过大会被看成无穷大。二是通过float()函数转换成'inf''-inf',这样能分别得到正无穷和负无穷。三是通过numpy包中的np.inf来得到无穷大的值:

print(1e10000)	# 10的10000次方
print(float('inf'), float('-inf'))
print(np.inf, np.PINF, np.NINF)		# PINF和NINF分别指示正无穷和负无穷

输出结果如下:

inf
inf -inf
inf inf -inf

(2)比较运算

无穷大之间的比较结果相等的,一些大到被系统认为是无穷大的常数和inf也相等。

print(float("inf") == float("inf"))
print(np.inf == np.inf)
print(1e10 < np.inf)
print(1e10000 == np.inf)

输出结果如下:

True
True
True
True

(3)算术运算

inf 可以进行各类运算,在和一般的常数做运算时,就和我们在数学里学过的一样的结果。除此以外,无穷➗无穷、无穷✖0时会返回nan。这个nan就是后面所要提到的not a number值:

1 + np.inf,  1 - np.inf,  np.inf * np.inf,  np.inf / np.inf,  np.inf * 0

输出结果如下:

(inf, -inf, inf, nan, nan)

同时,因为inf数据类型是浮点数,将它直接除以0是会报错的:

1/ 0 			   # 报错1
float('inf') / 0   # 报错2
np.inf / 0		   # 报错3
【报错1】ZeroDivisionError: division by zero
【报错2】ZeroDivisionError: float division by zero
【报错3】ZeroDivisionError: float division by zero

numpy除了np.PINF, np.NINF之外,还有np.PZEROnp.NZERO指示正0和负0,它们与无穷相乘也会返回nan值。这两个用来描述0的常量应用的比较少。

3、NaN

它是not a number值,这个值是我们大部分数据分析任务中空值的表示方式,包括读取的数据文件结果中空值的表示方式(而不是None)。

(1)数据类型

nan值作为浮点型数据,可以做任何浮点型数据可以做的数值运算,但返回结果都是nan。此外,与inf相同,nan值不允许除以0:

print(np.nan + 2)
print(np.nan * 4)
print(np.nan + nan)
print(np.nan / nan)
print(np.nan / 0) 		# 报错,作为浮点型数据,不允许直接除以零

输出结果如下:

nan
nan
nan
nan
ZeroDivisionError: float division by zero

(2)比较运算

nannan并不相等,而且所有关于nan值的大小比较结果都是False

print(np.nan == np.nan)
print(np.nan != np.nan)
print(np.nan < np.nan)
print(np.nan < 1e100)

输出结果如下:

False
True
False
False

(3)判别

np.nan这个值可以用is相互判别,但是从字符串转化的nan,用is做判别是无法获得True

print(np.nan is np.nan)
print(float('nan') is np.nan)
print(float('nan') is float('nan'))

输出结果如下:

True
False
False

因此,为了解决以上判断空值的问题,我们这里给出两种解决办法。第一种是引入外部的math包或numpy包,math.isnan()或是np.isnan()函数可判断空值,前者不能接列表或numpy数组,而后者可以。

import math
import numpy as np
math.isnan(float('nan'))
np.isnan(float('nan'))

输出结果如下:

True
True

但这两个函数还有一个缺陷,即他们仅能判别数值(或全为numpy数组)是否为nan,在遇上字符串的时候会报错,这样便无法检验一个字符串列有多少空值。这时候我们在此介绍第二种方法。
这个方法利用的是nannan并不相等,而除此之外其他一般的异常值都和自己相等这样一个特性,因此下列的方法也可以利用,即让自己比较自己。

a = np.array([1, 2, float('nan'), np.nan])
print(a == a)
[ True  True False False]

我们通过这种方法来判别空值时,对后续结果处理显得很方便。例如由于因为这种比较能够在任意一个数据类型的numpy数组或列表中进行,因此可以直接利用比较的结果统计缺失值的个数:

print(sum(a != a))
2

二、if x和bool(x)的返回值

在这里给大家补充一点关于if语句在接单一变量时候的效果。对于if接单一变量,如果是空值(包括空列表、字符串、字典等)、False或者是0,这个语句表示False,反之,它非空的时候表示真。我们这里写如下的函数来展示if语句返回结果:

def ifa(a):
    if a:
        return True
    else:
        return False
        
print(ifa(None), ifa(''), ifa(0), ifa([]), ifa({}),ifa(False))
print(ifa(np.nan), ifa(np.inf), ifa('String'), ifa(-1), ifa([1, 2, 3]), ifa(True))

输出结果如下:

False False False False False False
True True True True True True

从结果上说,内置函数bool(x)就是实现了刚刚ifa()函数的过程:

print(bool(None), bool(''), bool(0), bool([]), bool({}),bool(False))
print(bool(np.nan), bool(np.inf), bool('String'), bool(-1), bool([1, 2, 3]), bool(True))

输出结果如下:

False False False False False False
True True True True True True

关于if a表示真或者假,其判断过程可以归结如下:

1、调用a的__nonzero__()去判断a是否为空,并返回True/False。
2、若一个对象没有定义__nonzero__(),就去调用它的__len__()来进行判断(这里返回值为0代表空)。
若某一对象没有定义以上两种方法,则if a的结果为True。

在此做一个补充,之前所述np.inf和0相乘的结果为nan,这个nan不是np.nan值,请务必注意,这里做一个实验如下:

print(id(np.PZERO * np.PINF) is np.nan)
print(id(0 * np.inf) is np.nan)

输出结果如下:

False
False

三、is运算符和元素的内存地址ID

is判别的是两个变量是否是一个相同的对象。在上节提过,对于利用float()转换的nan值,包括读取文件结果中的空值,is的判断结果会是False。其实,这里面的原因是: == 比较的是两个变量的的值,而is实际上比较的是两个元素的内存地址。
查看元素a的内存地址用id(a)进行。这里需要注意的是:先后用同样的值定义两个同样的变量,它的内存地址不一定一样。首先查看列表、元组、字典、集合,可以发现先后用同样的值定义两个变量,内存id相互不一样,而is就会返回False。但是,如果用等于号赋值,两个值的内存位置就是一样的,is运算的返回的结果就是True。我们对此分别进行验证如下:

a_list, b_list = [1, 2], [1, 2]
a_tuple, b_tuple = (3, 4), (3, 4)
a_dict, b_dict = {'5': 5, '6': 6}, {'5': 5, '6': 6}
a_set, b_set = {7, 8}, {7, 8}
a_list_2, a_tuple_2, a_dict_2, a_set_2 = a_list, a_tuple, a_dict, a_set 

print(a_list == b_list, id(a_list) == id(b_list), a_list is b_list, a_list is a_list_2)
print(a_tuple == b_tuple, id(a_tuple) == id(b_tuple), a_tuple is b_tuple, a_tuple is a_tuple_2)
print(a_dict == b_dict, id(a_dict) == id(b_dict), a_dict is b_dict, a_dict is a_dict_2)
print(a_set == b_set, id(a_set) == id(b_set), a_set is b_set, a_set is a_set_2)

输出结果如下:

True False False True
True True True True
True False False True
True False False True

另外,用is来判断两个元素是否为同一个值时,还存在许多细节问题,需要仔细注意。在必须使用它编写程序处理数据分析任务时,可以先执行一些实验代码确认效果。

以上就是运用python进行数据分析时,一些导致数据分析代码不能如期运行的原因及解决方案。


对于缺乏Python基础的同仁,可以通过免费专栏🔥《Python学习笔记(基础)》从零开始学习Python

结语

请始终相信“Done is better than perfect” ,不要过分追求完美,即刻行动就是最好的开始, 一个模块一个模块地积累和练习,必将有所收获。
还有其他的问题欢迎在评论区留言📝!


[版权申明] 非商业目的注明出处可自由转载,转载请标明出处!!!
博客:butterfly_701c

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值