实习是关于机器学习的一个项目,博主渣硕之前只有学过Python的基础,没有Python方面的项目经历。鉴于目前Python在机器学习方面的火爆,以及对Python未来的看好。决定用Python来,希望能够完成实习任务。推荐一个很好的Data Science方向在线学习网站DATAQUEST。该网站部分免费,免费部分也很有意思,思路非常清晰。本文只介绍NumPy的常用的基本操作。
本来想自己敲代码,演示下。但是原文的数据集: world_alcohol.csv 我没有找到,所以我只能“翻译”原文了。教程中的数据如下表所示(后续的联系都是基于这个数据集):
Year | Region | Country | Beverage Types | Display Value |
---|---|---|---|---|
1986 | ‘Western Pacific’ | ‘Viet Nam’ | ‘Wine’ | 0 |
1986 | ‘Americas’ | ‘Uruguay’ | ‘Other’ | 0.5 |
1985 | ‘Africa’ | ‘Cte d’Ivoire’ | ‘Wine’ | 1.62 |
每行代表改国家在某年某类饮品的人均消费量(单位:升)。比如1986年越南人均酒的消费量为0升
列表的列表,其实就是矩阵 (Matrix)。原生的Python就支持此操作。在介绍NumPy之前,先介绍Python原生操作。这样方便对比两者之间的优劣。
world_alcohol.csv 中的数据是表格的形式存在的,其实就是矩阵啦。下面是数据集中的几个数据展示。
world_alcohol = [
[1986, "Western Pacific", "Viet Nam", "Wine", 0],
[1986, "Americas", "Uruguay", "Other", 0.5],
[1986, "Africa", "Cte d'Ivoire", "Wine", 1.62]
]
我们能用list的操作来得到第一行数据:
first_row = world_alcohol[0]
first_row 的内容是:
[1986, "Western Pacific", "Viet Nam", "Wine", 0]
first_row[0] 能得到1986, first_row[1]能得到Wine。第一个index取得相应的行,第二个index取得相应的列。行列号都是从0开始的。比如world_alcohol[1][1]能德高‘Americas’。
原生Python中不方便的地方是计算统计值。比如我们想计算Display Value的平均值,我们必须要循环遍历数组,如下:
>>> liters_drank = []
>>> for row in world_alcohol:
... liters_drank.append(row[4])
>>> liters_drank = liters_drank[1:len(liters_drank)]
>>> total = 0
>>> for item in liters_drank:
... total = total + float(item)
>>> print(sum(liters_drank) / len(liters_drank))
我们可以看到,用原生list计算数据统计数值的时候,需要遍历list,这样很不方便。NumPy引入了对矩阵的统计方法。
Numpy比Python原生的数组,矩阵操作高效多了。Numpy是Python用来操作多维数组的一个模块。它效率更高,提供的接口方法更多。
>>> import numpy
>>>
>>> vector = numpy.array([5, 10, 15, 20])
>>> import numpy
>>>
>>> world_alcohol = numpy.genfromtext('world_alcohol.csv', delimiter = ',' =)
可以用dtype属性来查看数据类型,一个NumPy数组只支持一种数据类型。NumPy可支持的数据类型有:
读取world_alcohol.csv会发现,里面有数据类型na (Not Available)和nan (Not A Number),前者表示读取的数值是空的,是不存在的。后者是因为数据类型转换出错。
>>> numbers = numpy.array([1, 2, 3, 4])
>>> print(numbers.dtype)
int64
# the datatype is int64
通过shape属性能够查看array的大小, 或者通过shape()方法查看
>>> vector1 = numpy.array([1, 2, 3, 4])
>>> # use shape property to print
>>> print(vector1.shape)
4
>>> vector2 = numpy.array([[1, 2, 3], [4, 5, 6]])
>>> # use shape() method to print
>>> print(numpy.shape(vector2))
(2, 3)
我们在数据类型这段提到过nan错误,我们可以用genfromtxt()来转化数据类型。对于world_alcohol.csv我们可以这样做:
>>> import numpy
>>> import csv
>>> world_alcohol_csv = csv.reader(open('world_alcohol.csv'))
>>> world_alcohol = numpy.genfromtxt('world_alcohol.csv', dtype='U75', delimiter=',', skip_head=True)
NumPy支持list一样的定位操作。
>>> matrix = numpy.array([
... [5, 10, 15],
... [20, 25, 30]
... ])
>>> print(matrix[1, 2])
30
NumPy支持list一样的切片操作。
>>> matrix = numpy.array([
... [5, 10, 15],
... [20, 25, 30],
... [35, 40, 45]
... ])
>>> print(matrix[:1])
[[ 5 10 15]]
>>> print(matrix[:,1])
[10 25 40]
>>> print(matrix[1:3, 0:2])
[[20 25]
[35 40]]
NumPy最强大的地方是数组的比较。数组比较会产生boolean值。
对数组的比较:
>>> vector = numpy.array([1, 2, 3, 4])
>>> vector == 1
array([ True, False, False, False], dtype=bool)
对矩阵的比较:
>>> matrix = numpy.array([
... [5, 10, 15],
... [20, 25, 30],
... [35, 40, 45]
... ])
>>> matrix == 25
array([[False, False, False],
[False, True, False],
[False, False, False]], dtype=bool)
现在我们做一个练习,在world_alcohol.csv中:
>>> import numpy
>>>
>>> # 重新演示如何从csv文件中生成矩阵
>>> world_alcohol = numpy.genfromtxt('world_alcohol.csv', dtype='U75', delimiter=',', skip_header=True)
>>>
>>> countries_canada = (world_alcohol[:, 2] == 'Canada')
>>> years_1984 = (world_alcohol[:, 0] == '1984')
现在我们要体验一下为什么数组比较是这么强大。我们可以用数组比较得到的布尔值来条件取值。
在数组中:
>>> vector = numpy.array([5, 10, 15, 20])
>>> print(vector)
[ 5 10 15 20]
>>> equal_to_ten = (vector == 10)
>>> print(equal_to_ten)
[False True False False]
>>> # 输出只有相对于位布尔值是True位置上的值
>>> print(vector[equal_to_ten])
[10]
在矩阵中:
>>> matrix = numpy.array([
... [5, 10, 15],
... [20, 25, 30],
... [35, 40, 45]
... ])
>>> second_column_25 = (matrix[:,1] == 25)
>>> print(second_column_25)
[False True False]
>>> print(matrix[second_column_25, :])
[[20 25 30]]
>>>
在这段代码中:
现在做一个小练习,在world_alcohol中获取国家是Algeria(阿尔及利亚)的数据:
>>> country_is_algeria = world_alcohol[:, 2] == 'Algeria'
>>> country_algeria = world_alcohol[country_is_algeria, :]
我们没有world_alcohol.csv的数据集,我贴一份从DATAQUEST上得到的运行结果吧
ndarray (<class 'numpy.ndarray'>) array([['1984', 'Africa', 'Algeria', 'Spirits', '0.01'], ['1987', 'Africa', 'Algeria', 'Beer', '0.17'], ['1987', 'Africa', 'Algeria', 'Spirits', '0.01'], ['1986', 'Africa', 'Algeria', 'Wine', '0.1'], ['1984', 'Africa', 'Algeria', 'Other', '0'], ['1989', 'Africa', 'Algeria', 'Beer', '0.16'], ['1989', 'Africa', 'Algeria', 'Spirits', '0.01'], ['1989', 'Africa', 'Algeria', 'Wine', '0.23'], ['1986', 'Africa', 'Algeria', 'Spirits', '0.01'], ['1984', 'Africa', 'Algeria', 'Wine', '0.12'], ['1985', 'Africa', 'Algeria', 'Beer', '0.19'], ['1985', 'Africa', 'Algeria', 'Other', '0'], ['1986', 'Africa', 'Algeria', 'Beer', '0.18'], ['1985', 'Africa', 'Algeria', 'Wine', '0.11'], ['1986', 'Africa', 'Algeria', 'Other', '0'], ['1989', 'Africa', 'Algeria', 'Other', '0'], ['1987', 'Africa', 'Algeria', 'Other', '0'], ['1984', 'Africa', 'Algeria', 'Beer', '0.2'], ['1985', 'Africa', 'Algeria', 'Spirits', '0.01'], ['1987', 'Africa', 'Algeria', 'Wine', '0.1']], dtype=')
NumPy可以运用布尔值来替换值。
在数组中:
>>> vector = numpy.array([5, 10, 15, 20])
>>> equal_to_ten_or_five = (vector == 10) | (vector == 5)
>>> vector[equal_to_ten_or_five] = 50
>>> print(vector)
[50, 50, 15, 20]
在矩阵中:
>>> matrix = numpy.array([
... [5, 10, 15],
... [20, 25, 30],
... [35, 40, 45]
... ])
>>> second_column_25 = matrix[:,1] == 25
>>> matrix[second_column_25, 1] = 10
>>>> print(matrix)
[[ 5 10 15]
[20 10 30]
[35 40 45]]
在这段代码中:
惯例,我们做一个小练习。将world_alcohol年份为1986的行替换成年份2014。
world_alcohol[world_alcohol[:, 0] == '1986', 0] = 2014
world_alcohol[world_alcohol[:, 3] == 'Wine', 3] = 'Grog'
偷个懒,数据就不粘上来了。
替换有一个很棒的应用之处,就是替换那些空值。之前提到过NumPy中只能有一个数据类型。刚才我们把所有的world_alcohol.csv中的值按String读取。所以原来的整形都被自动转换成String了。其中的空值我们很有必要把他们替换成其他值,比如数据的平均值或者把他们删除。这在大数据处理中很有必要。这里,我们演示把Display value中空值替换为0的操作。
>>> is_value_empty = world_alcohol[:, 4] == ''
>>> world_alcohol[is_value_empty, 4] = '0'
我们能用astype()方法来转换数据类型。
比如,把String转换成float。如下:
>>> vector = numpy.array(["1", "2", "3"])
>>> vector = vector.astype(float)
小练习,把world_alcohol.csv中Display value从String转换成Float:
>>> alcohol_consumption = world_alcohol[:, 4]
>>> alcohol_consumption = alcohol_consumption.astype(float)
NumPy内置很多计算方法。其中最重要的统计方法有:
>>> vector = numpy.array([5, 10, 15, 20])
>>> vector.sum()
50
矩阵例子:
>>> matrix
array([[ 5, 10, 15],
[20, 10, 30],
[35, 40, 45]])
>>> matrix.sum(axis=1)
array([ 30, 60, 120])
>>> matrix.sum(axis=0)
array([60, 60, 90])
有例子所示,axis = 1计算的是行的和,结果以列的形式展示。axis = 0计算的是列的和,结果以行的形式展示。
NumPy的基本操作介绍得差不多了,现在需要的就是练习啦。
Ex1:计算Canada 1986年的饮品消费总量。
>>> is_canada_1986 = (world_alcohol[:, 0] == '1986') & (world_alcohol[:, 2] == 'Canada')
>>> canada_1986 = world_alcohol[is_canada_1986, :]
>>> canada_1986[canada_1986[:, 4] == '', 4] = '0'
>>> canada_alcohol = canada_1986[:, 4]
>>> canada_alcohol = canada_alcohol.astype(float)
>>> total_canadian_drinking = canada_alcohol.sum()
解题方法很直接。基本思路就是先选出国家是Canada,年份是1986的数组。然后在调用NumPy内置的素描()方法。
Ex2:计算每个国家的饮品消费总量。
>>> totals = {}
>>> countries = world)alcohol[:2]
>>>
>>> for country in countries:
... is_country_1989 = (world_alcohol[:, 0] == '1989') & (world_alcohol[:, 2] == country)
... country_consumption = world_alcohol[is_country_1989, :]
... country_consumption[country_consumption[:, 4] == '', 4] = '0'
... country_alcohol = country_consumption[:, 4].astype(float)
... totals[country] = country_alcohol.sum()
Ex3:计算饮品消费总量最多的国家。
>>> highest_value = 0
>>> highest_key = None
>>>
>>>for key in totals.keys():
... if totals[key] > highest_value:
... highest_value = totals[key]
... highest_key = key
通过上面基本介绍和给出的列子,我们发现NumPy比list of lists更方便:
NumPy多数据的处理更快更高效,所以应用很广泛。特别是在机器学习方面。
同时,我们也注意到了NumPy的不足之处: