本章讲解python中的基本运算,在数据科学领域python有着举足轻重的作用。本教程的后续章节主要集中于python在数据科学领域的应用,包括基础语法,数据预处理,数据可视化,机器学习和数据预测。
2.1 基本运算
在jupyter notebook中实现运算,可以借助print()
函数,括号内直接输入算式即可。
print(2/4)
print(1+1)
输出的结果如下:
需要注意的是取余和乘方运算符:
%
表示取余,**
表示乘方,例如计算100元在年利率10%的情况下,7年后的本息和为:
print(100 * 1.1 ** 7)
2.2 变量和数据类型
在编程中提到变量,就不得不明确变量的赋值。通常在编程中使用等号=
表示赋值,而不是用于判定两个变量是否相等。
变量的赋值为将来的调用提供了便利,因此在后续的代码中,可以直接通过变量名来调用该变量。这里继续使用本息和的例子:
# create a variable: money
money = 100
# create a variable: growth_multiplier
growth_multiplier = 1.1
# get result
result = money * growth_multiplier ** 7
# print out result
print(result)
输出的结果和上面一样。
*注意:这里变量的定义看似让代码更复杂,原因在于代码量较少。在涉及较多变量的代码中,变量的定义非常重要
前面的运算我们使用了数值型变量,这种变量包含整型(int)和浮点型(float),分别表示证书和小数。此外还有其他常用的数据类型:
-
str
: 字符型,表示一段文字,这段文字可以是数字和符号,通常用单引号或双引号来表示字符型数据 -
bool
:逻辑型,只包含真(True)和假(False)两种类型,注意开头字母要大写
根据数据类型,我们可以定义不同类型的变量。python语法的简洁性在变量的定义上非常显著,例如定义一个字符型变量和一个逻辑型变量:
pig = "I am a pig"
really = True
2.3 字符串的运算
python中,我们也可以对字符串进行运算,这种运算不同于前面提到的基础运算。
我们可以利用加号将两个字符串连结起来,也可以用乘法对字符串进行多次复制。
不难发现,这两个字符串被无缝连结起来了,这与阅读习惯不符合,因此我们考虑再加入一个空格以区分两个字符串:
接下来用乘法:
*注意:可以尝试通过变量的声明来进行输出
2.4 类型转换
试想一个场景,一个字符串的内容是一串数字,那么我们是否可以将这串数字转换成整型或浮点型数据以进行基本数值运算?答案是可以的。
# 定义一个字符型变量
pi_str = '3.14159'
#将字符型转换成浮点型并输出数据类型
pi_float = float(pi_str)
print(type(pi_float))
类型转换的另一个目的是便于输出,因为在使用print函数将多个字符串连结起来时,要求各元素拥有相同的数据类型,如下:
# create a variable: money
money = 100
# create a variable: growth_multiplier
growth_multiplier = 1.1
# get result
result = money * growth_multiplier ** 7
# more detailed output
print('I started with ' + str(money) + 'CNY and now have ' + str(result) + 'CNY, cool!!')
2.5 复合数据类型
2.5.1 列表的创建
前面介绍了基础的数据类型,接下来更深入一层,引入容器的概念。
第一个 容器是列表list, 顾名思义,容器类型可以容纳多个基础类型(甚至容器中可以包含其他的容器,这一点会在后面的章节详细讲述)。
*在R语言教程中,我提到了向量的概念,向量只能容纳同一数据类型的多个变量,别混了
在python中我们可以通过中括号来创建列表,然后赋值给一个变量名:
a = 'my'
b = 'first'
c = 'list'
my_first_list = [a, b, c]
my_first_list
*注意:也可以利用
.list()
函数来创建列表,括号内只能有一个argument,该函数的用法会在后面讲到
在第一个列表的例子中,列表中各个元素的类型都是字符型,下面进行扩展,尝试在同一个列表中列出房间名称(字符型)和房间面积(浮点型)两种类型:
# area variables in square meters
hall = 11.25
kit = 18.0
liv = 20.0
bed = 10.75
bath = 9.5
# adapt list areas
areas = ['Hallway', hall, 'Kitchen', kit, 'Living room', liv, 'Bedroom', bed, 'Bathroom', bath]
print(areas)
一个思考题,下面那段代码能成功创建一个列表?
- A.
[1, 2, 4, 3]
- B.
[[1, 2, 3], [4, 5, 6]]
- C.
[1 + 2, "a" * 5, 3]
正确答案是A,B,C
上面房间面积的例子的输出结果并不直观,因此尝试将列表的元素换成列表,即每个房间和其对应的面积包含在同一个列表中:
# area variables in square meters
hall = 11.25
kit = 18.0
liv = 20.0
bed = 10.75
bath = 9.5
# house information as list of lists
house = [['Hallway', hall], ['Kitchen', kit], ['Living room', liv], ['Bedroom', bed], ['Bathroom', bath]]
print(house)
print(type(house))
现在我想从areas
这个列表中选择某些特定的元素,例如我想知道厨房的面积,该怎么做?
借助列表元素的索引可以很方便地实现这个需求:
# 厨房的面积是:
print(areas[3])
*注意:python中列表的索引从0开始,与R语言不同,因此厨房的面积作为第四个元素,拥有的索引是3
我们也可以使用负数作为索引,用于选取列表中较为靠后的元素。python规定,-1表示倒数第一个元素,-2表示倒数第二个元素并以此类推。在areas列表中,末尾元素是9.5,我们尝试使用索引:
选出列表中的部分元素的目的在于,使用这些元素进行运算,例如我们可以计算house中起居室和厨房的面积和。
2.5.2 slice和dice选择多个列表元素
记住以下公式:
my_list[start: end]
*注意:这里的start被包含在所选元素中,而end不被包含,类似于区间[start, end)
这里再介绍一个用于选择前n个元素或后n个元素的捷径:
如果start空着不填,则表示从第一个元素(索引为0)开始直到end;如果end空着,则表示从start开始直到最后一个元素(这里的最后一个元素被包含),以areas列表为例,规定位于楼上的房间是areas的后4 个房间,位于楼下的房间是前六个元素:
# area variables in square meters
hall = 11.25
kit = 18.0
liv = 20.0
bed = 10.75
bath = 9.5
# adapt list areas
areas = ['Hallway', hall, 'Kitchen', kit, 'Living room', liv, 'Bedroom', bed, 'Bathroom', bath]
# Use slice to create upstairs(the last 4 elements)
upstairs = areas[-4: ]
# Use slice to create downstairs(the first 6 elements)
downstairs = areas[ : 6]
print(f'upstairs: {upstairs}\ndownstairs: {downstairs}')
*注意:通过本例我们知道,在使用slice时,引号左边的数字无论正负,都被包含,右边的则不被包含
2.5.3 subset嵌套列表
嵌套列表中的元素也是列表,因此如果我们想获取子列表中的元素,需要使用两次中括号,即第一次选择元素,第二次选择元素的元素:
# area variables in square meters
hall = 11.25
kit = 18.0
liv = 20.0
bed = 10.75
bath = 9.5
# house information as list of lists
house = [['Hallway', hall], ['Kitchen', kit], ['Living room', liv], ['Bedroom', bed], ['Bathroom', bath]]
print(house[1])
print(house[1][-1])
2.5.4 替换列表元素
有时候我们需要更改现存列表中的部分数值,但是重新定义整个列表会带来过多的工作量,因此我们需要单独对某些元素进行修改。方法很简单,借助上一节学到的subset获取子集,然后对该子集进行重新赋值。
例如,在areas列表中,浴室的面积应该是10.5平,而不是9.5平,我们进行如下修改:
# area variables in square meters
hall = 11.25
kit = 18.0
liv = 20.0
bed = 10.75
bath = 9.5
# adapt list areas
areas = ['Hallway', hall, 'Kitchen', kit, 'Living room', liv, 'Bedroom', bed, 'Bathroom', bath]
areas[-1] = 10.5
print(areas)
2.5.5 增加列表的元素
在数据搜集不完全的情况下,我们经常会对现有数据进行扩展,换句话说我们需要在现有列表中增加新的数据。这一操作可以通过加号来实现,例如我们在areas列表中增加车库数据:
# area variables in square meters
hall = 11.25
kit = 18.0
liv = 20.0
bed = 10.75
bath = 9.5
# adapt list areas
areas = ['Hallway', hall, 'Kitchen', kit, 'Living room', liv, 'Bedroom', bed, 'Bathroom', bath]
areas_whole = areas + ['Garage', 15.4]
print(areas_whole)
*注意:扩展列表时,使用加号连结的是两个列表
2.5.6 删除列表数据
若要删除列表的某个元素,可以借助del()
我们删除areas_whole列表中的前两个元素,来看看会发生什么,注意slice的用法:
# delete the first two elements and show the output
del(areas_whole[0:2])
print(areas_whole)
*注意:在执行del语句后,原列表中,位于被删除元素后面的元素的索引都会发生改变。可以理解为,删除部分元素后我们得到了一个新的列表,新列表的索引是从0开始逐个排列的
2.5.7 list的底层逻辑
本节将介绍python中list的存储逻辑,我们先创建一个列表,然后创建他的副本,并尝试改变副本中某元素的值,看看会发生什么:
some_list = [1, 2, 3, 4, 5]
some_list_copy = some_list
print(some_list)
print(some_list_copy)
some_list_copy[0] = -1
print(some_list)
print(some_list_copy)
改变副本,原始列表也发生改变,原因是当我们创建列表时,会在内存中开辟一个地址用于存储列表的内容,列表对应的变量名只是一个指向该地址的指针。当我们把列表的名称赋给另外一个变量名时,并没有重新开辟地址,新的名字仍然指向原本的地址,因此无论我们通过哪个名字对存放在该地址中的列表进行修改,该列表都已经发生了改变。
那么能否避免这种情况?当然可以。只需要开辟另外一个地址即可。借助list()
函数重新创建一个列表:
some_list = [1, 2, 3, 4, 5]
some_list_copy = list(some_list)
print(some_list)
print(some_list_copy)
some_list_copy[0] = -1
print(some_list)
print(some_list_copy)
另外一种与list()
等效的方法如下,使用slice:
some_list = [1, 2, 3, 4, 5]
some_list_copy = some_list[: ]
print(some_list)
print(some_list_copy)
some_list_copy[0] = -1
print(some_list)
print(some_list_copy)
2.6 函数function
2.6.1 函数的调用
python中的函数跟数学中的函数类似,通常包括自变量(输入值),因变量(输出值)和映射关系(函数所实现的功能)。其实到目前为止我们不经意间已经使用了函数,例如print()是用于输出的内置函数,type()是用来返回某个变量类型的内置函数。除了内置函数,我们也可以进行自定义,以实现我们需要的功能。
函数的调用过程如下:
type = type(1.0)
即:通过调用type()函数,将1.0的类型赋给变量type。
更普遍地,output = function_name(input)
此外,函数还可以叠加使用,例子如下:
var_1 = [1, 2, 3, 4]
var_2 = True
# print out type of var_1
print(type(var_1))
# print out length of var_1
print(len(var_1))
# convert var_2 into an integer
var_2_int = int(var_2)
# check the type of var_2_int
print(type(var_2_int))
2.6.2 help() 和?
python中有数量庞大的函数,我们并不需要记住所有函数的用法。当我们需要知道某个函数的具体用法时,可以借助help()或?来查询。
例如我想知道max()函数的用法,只需要将函数名输入在help()的括号里,或问号的后面:
*注意:查询帮助文档时,只需要输入函数名,被查询函数的括号不用写
2.6.3 多个自变量
上一节的max函数只需要一个可迭代的自变量,但很多情况下我们使用的函数需要多个自变量(argument),以sorted函数为例,首先查询该函数的具体用法:
我们得知,该函数需要一个可迭代对象(列表等容器类型)作为输入值,key在这里先不讲,reverse默认为假。
函数的功能也有详细的叙述,即返回一个列表,该列表包含可迭代对象的所有元素且按照升序排列(由此可知,当reverse为真时,返回的列表按照降序排列)。
下面是具体的例子:
a_list = [2, 6, 8, 4, 0, 5, -1]
list_asc = sorted(a_list)
list_desc = sorted(a_list, reverse = True)
print(f'in ascending order: {list_asc}\nin descending order: {list_desc}')
*注意:函数的可选参数(如reverse)是可以省略的
2.7 方法method
方法和函数很容易混为一谈。我们可以简单地把方法理解为隶属于某些对象的函数,例如一个字符串类型的对象拥有不同的方法,我们可以将一串小写字母改成大写。
方法的调用需要使用.
运算符。接下来是字符类型方法的具体例子:
place = 'poolhouse'
# 将place改成大写
place_up = place.upper()
print(place)
print(place_up)
# 计数place中有几个字母o
print(place.count('o'))
除了字符类型的对象有自己的方法之外,列表、浮点型、整型以及逻辑型都有许多有用的方法,大大提高了数据分析的效率。
例如index方法,可用于输出列表中第一个与输入值匹配的元素的索引,count方法可用于输出列表中某元素出现的次数。
some_list = [6, 9, 10, 13, 10, 5, 8]
print(some_list.index(10))
print(some_list.count(10))
在前面的章节我们介绍了怎样在列表中增加或删除元素,增加元素我们使用了加号,删除元素我们使用了del函数。现在介绍怎样通过方法来实现:
- 增加元素:
append()
some_list = [6, 9, 10, 13, 10, 5, 8]
some_list.append(-100)
print(some_list)
*注意:使用append方法时,括号内直接填写需要增加的元素值,而使用加号时必须保证被连接的是两个列表
- 颠倒列表元素的顺序:
reverse()
:
some_list = [6, 9, 10, 13, 10, 5, 8]
some_list.append(-100)
print(some_list)
some_list.reverse()
print(some_list)
*注意:由此可知列表类型是有顺序的,要与后面讲到的集合类型区分开
- 删除元素
remove()
: 删除列表中第一个与输入元素匹配的元素
2.8 包
提到python的强大,不得不提python中的包或库。本节将会介绍几种数据分析常用的包,以及如何安装和调用包。
2.8.1 包的安装
很多教程会告诉我们,要使用cmd命令提示符来安装包,但事实上我们可以省略这一步,直接在VS code中安装,我想安装sklearn这个包,命令如下:! pip install sklearn
, 然后运行,等待一段时间我们就会看到代码运行的结果如下:
2.8.2 包的导入
在包安装成功后,要想使用这个包,我们还需要导入该包。这里用math包举例(因为目前还没讲到机器学习,用不到sklearn)
math包里面包含了常用的数学常数例如圆周率,我们可以更精确地计算圆的面积和周长。
import math
r = 0.43
C = 2 * math.pi * r
A = math.pi * r ** 2
print('Circumference: ' + str(C))
print('Area: ' + str(A))
2.8.3 Numpy
本节将正式进入数据科学的领域,在前面的章节介绍了列表这种容器,但是我们不难发现,我们很难对列表的元素进行数学运算。事实上列表更适用于容纳并展示信息。
当我们需要对一组数据进行加减乘除等数学运算时,会用到另一种容器:数组(array),这种容器的使用需要Numpy包。
本节将会使用一组足球运动员的身高和体重数据,并计算他们的BMI指数。
BMI = weight(kg) / height(m)^2
首先创建一个列表,包含7名运动员的身高cm,然后使用缩写np导入numpy以简化后续使用,再将身高数据列表转换成数组并检查数据类型:
# create a list of height in cm
height_cm = [183, 175, 173, 188, 172, 180, 177]
# import numpy package as np
import numpy as np
# create a numpy array from height_cm
np_height_cm = np.array(height_cm)
# check the type of np_height_cm
print(type(np_height_cm))
输出结果是np数组,说明转化成功,接下来将单位厘米改成米,并计算BMI:
# create a list of weight in kg
weight = [80, 77, 78, 83, 75, 90, 86]
np_weight = np.array(weight)
# convert cm in m
np_height_m = np_height_cm / 100
# calculate bmi
bmi = np_weight / np_height_m ** 2
# print out bmi
print(bmi)
print(type(bmi))
2.8.4 subset array
前面的章节介绍了怎样筛选列表中的多个元素,下面介绍np数组中如何选择元素。
首先,数组的一个很大的优势在于,我们可以借助由逻辑值组成的数组对现有数组进行筛选。例如作为球队的教练,我想知道体重较轻(BMI < 24)的球员的身高体重数据,做法如下:
light = bmi < 24
print(light)
# print out BMIs of all players whose BMI is below 24
print(bmi[light])
*注意:借助逻辑值组成的数组来进行筛选符合某些特定条件的值,是数据分析中常用的手段
当然,我们同样也可以省略light,这种方法会在后面介绍data frame的时候用到:
除此之外,数组也可以像列表那样进行slice,用法完全一致这里不再赘述
2.8.5 np array和list的区别
np array只能包含某一个数据类型的值,而list可以包含多个不同的数据类型的值。
加减乘除对于数组和列表也有不同的含义,两个列表相加时,我们会得到一个被扩展的列表,而不是进行元素水平的加法运算(数组相加,则会进行元素水平的相加)
2.8.6 二维数组
我们已经从列表创建了一维数组,现在我们尝试从列表的列表创建二维数组,所用到的函数仍是np.array()
:
football = [[183, 80], [175, 77], [173, 78], [188, 83], [172, 75], [180, 90], [177, 86]]
np_football = np.array(football)
print(np_football)
print(type(np_football))
print(np_football.shape)
*注意:shape是数组的一个定语,可以理解为特征,用(行数,列数)来表示
2.8.7 二维数组的筛选
当我们选择列表的列表中的元素时,第一个中括号用于选择整个列表的元素,即子列表;第二个中括号用于选择子列表的具体元素。
而在数组中,我们只需要一个中括号即可完成,在中括号内用逗号分隔所选的行和列,左边是行右边是列。在选择具体的行或列时,需要用到冒号:
下面的代码可以帮助我们更好地理解元素级别的运算:
2.8.8 使用numpy做描述统计
本节介绍如何使用np进行描述分析,包括计算平均数,中位数,协方差等。
# print the mean height
avg = np.mean(np_football[: , 0])
print("Average: " + str(avg))
# print the median height
med = np.median(np_football[: , 0])
print("Median: " + str(med))
# print the standard deviation on height
std = np.std(np_football[:, 0])
print('Standard Deviation: ' + str(std))
# print out correaltion between the first and second columns
corr = np.corrcoef(np_football[:, 0], np_football[:, 1])
print('Correlation: ' + str(corr))