Numpy是python数据分析和科学计算的核心软件包。这是numpy教程的第2部分。在这一部分中,我将详细介绍numpy的高级功能,这些功能对于数据分析和操作非常重要。
1. 使用np.where获取满足给定条件的索引位置
上篇文章,你看到了如何从数组中提取满足给定条件的项目。布尔索引,是否还记得?
但有时我们想知道项目的索引位置(满足一个条件),并做任何你想做的事情。np.where
定位数组中给定条件成立的位置。
# Create an array
import numpy as np
arr_rand = np.array([8, 8, 3, 7, 7, 0, 4, 2, 5, 2])
print("Array: ", arr_rand)
# Positions where value > 5
index_gt5 = np.where(arr_rand > 5)
print("Positions where value > 5: ", index_gt5)
#> Array: [8 8 3 7 7 0 4 2 5 2]
#> Positions where value > 5: (array([0, 1, 3, 4]),)
一旦你有了具体位置,你可以使用数组的take
方法来提取他们。
# Take items at given index
arr_rand.take(index_gt5)
#> array([[8, 8, 7, 7]])
值得庆幸的是,np.where
还接受2个更多的可选参数x和y。只要条件成立,'x'就会产生'y'。
下面,我尝试创建一个数组,每当条件为真时都会有字符串'gt5',否则,它会有'lt5'。
# If value > 5, then yield 'gt5' else 'le5'
np.where(arr_rand > 5, 'gt5', 'le5')
#> array(['gt5', 'gt5', 'le5', 'gt5', 'gt5', 'le5', 'le5', 'le5', 'le5', 'le5'],dtype='
我们还可以找到最大值和最小值的位置
# Location of the max
print('Position of max value: ', np.argmax(arr_rand))
# Location of the min
print('Position of min value: ', np.argmin(arr_rand))
#> Position of max value: 0
#> Position of min value: 5
好极了!
2. 将数据导入和导出为csv文件
导入数据集的标准方法是使用np.genfromtx
t函数。它可以从网址导入数据集,处理缺失值,多个分隔符,处理不规则数量的列等。
一个不太常用的版本是假设数据集没有缺失值的np.loadtxt
。
举个例子,让我们尝试从下面的URL读取一个.csv文件。由于numpy数组中的所有元素应该具有相同的数据类型,因此默认情况下,最后一个文本类型数据列将作为“nan”导入。
通过设置filling_values
参数,你可以用其他值替换缺失的值。
# Turn off scientific notation
np.set_printoptions(suppress=True)
# Import data from csv file url
path = 'https://raw.githubusercontent.com/selva86/datasets/master/Auto.csv'
data = np.genfromtxt(path, delimiter=',', skip_header=1, filling_values=-999, dtype='float')
data[:3] # see first 3 rows
#> array([[ 18. , 8. , 307. , 130. , 3504. , 12. , 70. ,
#> 1. , -999. ],
#> [ 15. , 8. , 350. , 165. , 3693. , 11.5, 70. ,
#> 1. , -999. ],
#> [ 18. , 8. , 318. , 150. , 3436. , 11. , 70. ,
#> 1. , -999. ]])
看上去很整齐。但是你是否注意到最后一列中的所有值都具有相同的值'-999'?
发生这种事上面提到过。D型=” float'
。文件中的最后一列包含文本值,因为numpy数组中的所有值都必须是相同的dtype
,np.genfromtxt
不知道如何将其转换为浮点数。
2.1 处理包含数字和文本列的数据集
在这种情况下,你必须按照原样使用文本列而不用占位符替换它,你可以将dtype设置为object
或None
。
# data2 = np.genfromtxt(path, delimiter=',', skip_header=1, dtype='object')
data2 = np.genfromtxt(path, delimiter=',', skip_header=1, dtype=None)
data2[:3] # see first 3 rows
#> array([( 18., 8, 307., 130, 3504, 12. , 70, 1, b'"chevrolet chevelle malibu"'),
#> ( 15., 8, 350., 165, 3693, 11.5, 70, 1, b'"buick skylark 320"'),
#> ( 18., 8, 318., 150, 3436, 11. , 70, 1, b'"plymouth satellite"')],
#> dtype=[('f0', '
好极了!
最后,np.savetxt
可让你将数组导出为csv文件。
# Save the array as a csv file
np.savetxt("out.csv", data, delimiter=",")
3. 保存和加载numpy对象
在某些情况下,我们希望将大型转换后的numpy数组保存到磁盘并直接将其加载回控制台,而无需重新运行数据转换代码。
Numpy为此提供了.npy和.npz文件类型。
如果要存储单个ndarray对象,请使用np.save将其存储为.npy文件。这可以使用np.load
加载。
如果你想要将一个以上的ndarray对象存储在单个文件中,请使用np.savez
将其保存为.npz文件。
# Save single numpy array object as .npy file
np.save('myarray.npy', arr2d)
# Save multile numy arrays as a .npz file
np.savez('array.npz', arr2d_f, arr2d_b)
加载.npy文件
# Load a .npy file
a = np.load('myarray.npy')
print(a)
#> [[0 1 2]
#> [3 4 5]
#> [6 7 8]]
加载.npz文件
# Load a .npz file
b = np.load('array.npz')
print(b.files)
b['arr_0']
#> ['arr_0', 'arr_1']
#> array([[ 0., 1., 2.],
#> [ 3., 4., 5.],
#> [ 6., 7., 8.]])
4. 连接两个numpy数组的列式和行式###
有三种不同的连接两个或更多numpy数组的方法。
- 方法1:利用
np.concatenate
将轴参数更改为0和1 - 方法2:
np.vstack
和np.hstack
- 方法3:
np.r_
和np.c_
所有三种方法提供相同的输出,要注意的一个关键区别是与其他两种方法不同,np.r_
和np.c_
使用方括号来堆栈数组。但首先,让我创建要并置的数组。
a = np.zeros([4, 4])
b = np.ones([4, 4])
print(a)
print(b)
#> [[ 0. 0. 0. 0.]
#> [ 0. 0. 0. 0.]
#> [ 0. 0. 0. 0.]
#> [ 0. 0. 0. 0.]]
#> [[ 1. 1. 1. 1.]
#> [ 1. 1. 1. 1.]
#> [ 1. 1. 1. 1.]
#> [ 1. 1. 1. 1.]]
让我们垂直堆叠数组。
# Vertical Stack Equivalents (Row wise)
np.concatenate([a, b], axis=0)
np.vstack([a,b])
np.r_[a,b]
#> array([[ 0., 0., 0., 0.],
#> [ 0., 0., 0., 0.],
#> [ 0., 0., 0., 0.],
#> [ 0., 0., 0., 0.],
#> [ 1., 1., 1., 1.],
#> [ 1., 1., 1., 1.],
#> [ 1., 1., 1., 1.],
#> [ 1., 1., 1., 1.]])
那是我们想要的。再来个水平(列)堆叠
# Horizontal Stack Equivalents (Coliumn wise)
np.concatenate([a, b], axis=1)
np.hstack([a,b])
np.c_[a,b]
#> array([[ 0., 0., 0., 0., 1., 1., 1., 1.],
#> [ 0., 0., 0., 0., 1., 1., 1., 1.],
#> [ 0., 0., 0., 0., 1., 1., 1., 1.],
#> [ 0., 0., 0., 0., 1., 1., 1., 1.]])
此外,你可以使用np.r_
在一维数组中创建更复杂的数字序列
np.r_[[1,2,3], 0, 0, [4,5,6]]
#> array([1, 2, 3, 0, 0, 4, 5, 6])
5. 根据一列或多列对numpy数组进行排序
让我们尝试根据第一列对二维数组进行排序。
arr = np.random.randint(1,6, size=[8, 4])
arr
#> array([[3, 3, 2, 1],
#> [1, 5, 4, 5],
#> [3, 1, 4, 2],
#> [3, 4, 5, 5],
#> [2, 4, 5, 5],
#> [4, 4, 4, 2],
#> [2, 4, 1, 3],
#> [2, 2, 4, 3]])
我们有一个8行和4列的随机数组。
如果使用axis = 0的np.sort
函数,那么所有列将按照彼此独立的升序进行排序,从而有效地降低行项目的完整性。简而言之,每行中的值会被来自其他行的值破坏。
# Sort each columns of arr
np.sort(arr, axis=0)
#> array([[1, 1, 1, 1],
#> [2, 2, 2, 2],
#> [2, 3, 4, 2],
#> [2, 4, 4, 3],
#> [3, 4, 4, 3],
#> [3, 4, 4, 5],
#> [3, 4, 5, 5],
#> [4, 5, 5, 5]])
因为我不想让行的内容受到干扰,所以这里间接地采取np.argsort
来排序。
5.1 使用argsort对基于1列的numpy数组进行排序
我们先来了解一下np.argsort
的功能。 np.argsort
返回将使给定的一维数组排序的索引位置。
# Get the index positions that would sort the array
x = np.array([1, 10, 5, 2, 8, 9])
sort_index = np.argsort(x)
print(sort_index)
#> [0 3 2 4 5 1]
如何解释这一点? 在数组x
中,第0项是最小的,第3项是第2小的,以此类推。
x[sort_index]
#> array([ 1, 2, 5, 8, 9, 10])
现在,为了排序上面的arr数组,我将在第1列上执行一个参数,并使用结果索引位置对arr进行排序。看代码。
# Argsort the first column
sorted_index_1stcol = arr[:, 0].argsort()
# Sort 'arr' by first column without disturbing the integrity of rows
arr[sorted_index_1stcol]
#> array([[1, 5, 4, 5],
#> [2, 4, 5, 5],
#> [2, 4, 1, 3],
#> [2, 2, 4, 3],
#> [3, 3, 2, 1],
#> [3, 1, 4, 2],
#> [3, 4, 5, 5],
#> [4, 4, 4, 2]])
要按降序对其进行排序,只需颠倒argsorted
索引即可
# Descending sort
arr[sorted_index_1stcol[::-1]]
#> array([[4, 4, 4, 2],
#> [3, 4, 5, 5],
#> [3, 1, 4, 2],
#> [3, 3, 2, 1],
#> [2, 2, 4, 3],
#> [2, 4, 1, 3],
#> [2, 4, 5, 5],
#> [1, 5, 4, 5]])
5.2 如何基于2列或更多列对numpy数组进行排序?
你可以使用np.lexsort
通过传递一个基于数组应该排序的列的元组来执行此操作。 只要记住要将列首先排列在元组内的最右侧。
# Sort by column 0, then by column 1
lexsorted_index = np.lexsort((arr[:, 1], arr[:, 0]))
arr[lexsorted_index]
#> array([[1, 5, 4, 5],
#> [2, 2, 4, 3],
#> [2, 4, 5, 5],
#> [2, 4, 1, 3],
#> [3, 1, 4, 2],
#> [3, 3, 2, 1],
#> [3, 4, 5, 5],
#> [4, 4, 4, 2]])
6. 使用日期###
Numpy通过np.datetime64
实现日期对象,该对象支持精度直到纳秒。你可以使用标准的YYYY-MM-DD格式的日期字符串创建这样一个对象
# Create a datetime64 object
date64 = np.datetime64('2018-02-04 23:10:10')
date64
#> numpy.datetime64('2018-02-04T23:10:10')
当然,你可以通过几小时,几分钟,几秒直到纳秒。 让我们从date64
中删除时间组件
# Drop the time part from the datetime64 object
dt64 = np.datetime64(date64, 'D')
dt64
#> numpy.datetime64('2018-02-04')
默认情况下,如果添加数字会增加天数。但是,如果你需要增加其他时间单位(如月,小时,秒等),那么timedelta
对象非常方便。
# Create the timedeltas (individual units of time)
tenminutes = np.timedelta64(10, 'm') # 10 minutes
tenseconds = np.timedelta64(10, 's') # 10 seconds
tennanoseconds = np.timedelta64(10, 'ns') # 10 nanoseconds
print('Add 10 days: ', dt64 + 10)
print('Add 10 minutes: ', dt64 + tenminutes)
print('Add 10 seconds: ', dt64 + tenseconds)
print('Add 10 nanoseconds: ', dt64 + tennanoseconds)
#> Add 10 days: 2018-02-14
#> Add 10 minutes: 2018-02-04T00:10
#> Add 10 seconds: 2018-02-04T00:00:10
#> Add 10 nanoseconds: 2018-02-04T00:00:00.000000010
将dt64
转换回字符串。
# Convert np.datetime64 back to a string
np.datetime_as_string(dt64)
#> '2018-02-04'
处理日期时,你通常需要从数据中过滤掉工作日。你可以使用np.is_busday()
判断给定日期是否为营业日。
print('Date: ', dt64)
print("Is it a business day?: ", np.is_busday(dt64))
print("Add 2 business days, rolling forward to nearest biz day: ", np.busday_offset(dt64, 2, roll='forward'))
print("Add 2 business days, rolling backward to nearest biz day: ", np.busday_offset(dt64, 2, roll='backward'))
#> Date: 2018-02-04
#> Is it a business day?: False
#> Add 2 business days, rolling forward to nearest biz day: 2018-02-07
#> Add 2 business days, rolling backward to nearest biz day: 2018-02-06
6.1 创建一个日期序列
它可以简单地使用np.arange
本身完成
#Create date sequence
dates = np.arange(np.datetime64('2018-02-01'), np.datetime64('2018-02-10'))
print(dates)
# Check if its a business day
np.is_busday(dates)
#> ['2018-02-01' '2018-02-02' '2018-02-03' '2018-02-04' '2018-02-05'
#> '2018-02-06' '2018-02-07' '2018-02-08' '2018-02-09']
array([ True, True, False, False, True, True, True, True, True], dtype=bool)
6.2 将numpy.datetime64
转换为datetime.datetime
对象
# Convert np.datetime64 to datetime.datetime
import datetime
dt = dt64.tolist()
dt
#> datetime.date(2018, 2, 4)
一旦你将它转换为datetime.date
对象,你就有更多的工具来提取月份的日期,月份等
print('Year: ', dt.year)
print('Day of month: ', dt.day)
print('Month of year: ', dt.month)
print('Day of Week: ', dt.weekday()) # Sunday
#> Year: 2018
#> Day of month: 4
#> Month of year: 2
#> Day of Week: 6
7.0 总结
到目前为止,我们已经涵盖了许多使用numpy进行数据操作的技术。但是有很多事情你不能直接用numpy做...
所以接下来我们可以选择放弃一些难的numpy函数,寻求一些常用基本操作... 并且熟悉它们,所以那就必须有numpy 100练...大家可以去google然后锻炼一下