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.PZERO
和np.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)比较运算
nan
与nan
并不相等,而且所有关于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
,在遇上字符串的时候会报错,这样便无法检验一个字符串列有多少空值。这时候我们在此介绍第二种方法。
这个方法利用的是nan
与nan
并不相等,而除此之外其他一般的异常值都和自己相等这样一个特性,因此下列的方法也可以利用,即让自己比较自己。
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