Python Numpy高效数据处理(一)

做算法的,在工作中经常需要处理大量的数据,python中的for循环实在是太蠢了,写这篇博客主要是记录一下平时在处理大批量数据时,抛弃了for循环的新方法。本文基于python3.7

获取数组B中每个元素在数组A中的索引值

import numpy as np
import time

传统方法:for循环里使用list的index功能:

def get_index_from_array2(from_array, purpose_array):
    from_list = list(from_array)
    p_idx = np.in1d(purpose_array, from_array)      #筛选出 purpose_array 存在于 from_array 中存在的项,防止找不到索引而报错
    purpose_idx_in_from = -np.ones(purpose_array.shape).astype(int)     #初始化待返回的索引数组为-1,长度对应purpose_array
    in_len = p_idx.sum()                            #得到筛选之后的总数量
    tmp_p_array = purpose_array[p_idx]              #筛选之后的数组
    tmp_idx = np.zeros(in_len).astype(int)          #临时索引,长度对应筛选之后的数组
    for i in range(in_len):                         #循环得到所有可获取的索引值
        tmp_idx[i] = from_list.index(tmp_p_array[i])
    purpose_idx_in_from[p_idx] = tmp_idx            #待返回的索引数组赋值
    return purpose_idx_in_from

针对所有可能的情况,A可能包含B,也可能不完全包含B,所以先做了筛选,只针对筛选出来的部分查询索引值
调用测试:

purpose_array = np.array(['b', 't', 'd', 'g', 'f', 'f', 'g', 'b', 'g', 'f', 'p', 'd', 'f', 'r', 'g', 'w', 't', 'd', 'e', 'b', 'e'])
from_array = np.array(['e', 'c', 'f', 'a', 'e', 'g', 'f', 'a', 'b', 'd', 'd', 'e'])
idx = get_index_from_array2(from_array, purpose_array)
print(idx)
pos_idx = (idx != -1)
test_a = purpose_array[pos_idx]
test_b = from_array[idx[pos_idx]]
print((test_a == test_b).all())

测试中,去掉了索引是-1的部分,剩余部分进行比对,运行结果如下:

[ 8 -1  9  5  2  2  5  8  5  2 -1  9  2 -1  5 -1 -1  9  0  8  0]

结果完全一致!

改进1:采用map函数

直接上代码:

def get_index_from_array3(from_array, purpose_array):
    purpose_array = np.array(purpose_array)
    from_array = np.array(from_array)
    from_list = list(from_array)
    p_idx = np.in1d(purpose_array, from_array)
    purpose_idx_in_from = -np.ones(purpose_array.shape).astype(int)
    tmp_p_array = purpose_array[p_idx]
    tmp_idx = map(from_list.index, tmp_p_array)
    purpose_idx_in_from[p_idx] = list(tmp_idx)
    return purpose_idx_in_from

和上面没有太多区别,只是for循环用map代替,测试结果一致,不过多赘述

改进2:采用numpy数组操作,避开循环

还是先上代码:

def get_index_from_array(from_array, purpose_array):
    purpose_array = np.array(purpose_array)
    from_array = np.array(from_array)
    purpose_idx_in_from = -np.ones(purpose_array.shape).astype(int)     #初始化待返回的索引数组为-1,长度对应purpose_array
    p_idx = np.in1d(purpose_array, from_array)      #筛选出 purpose_array 存在于 from_array 中存在的项
    union_array = np.hstack((from_array, purpose_array[p_idx]))         #合并from_array 和从 purpose_array 中筛选出来的数组
    _, union_idx, union_inv = np.unique(union_array, return_index=True, return_inverse=True)    #unique函数得到索引值
    purpose_idx_in_from[p_idx] = union_idx[union_inv[len(from_array):]] #待返回的索引数组赋值
    return purpose_idx_in_from

这里介绍一下numpy中的unique函数,非常好用:
unique函数默认返回一个包含不重复的数组,并且包含原数组全部元素。该函数包含三个可选参数,return_index,return_inverse,return_count。看个例子:

from_array = np.array(['e', 'c', 'f', 'a', 'e', 'g', 'f', 'a', 'b', 'd', 'd', 'e'])
test = np.unique(from_array, True, True, True)
print(test)

返回结果:

(array(['a', 'b', 'c', 'd', 'e', 'f', 'g'], dtype='<U1'),
 array([3, 8, 1, 9, 0, 2, 5], dtype=int64),
 array([4, 2, 5, 0, 4, 6, 5, 0, 1, 3, 3, 4], dtype=int64),
 array([2, 1, 1, 2, 3, 2, 1], dtype=int64))

返回了四个数组:
第一个数组a,包含原数组所有元素的不重复的数组;
第二个数组b,每个元素在原数组中第一次出现的索引,和a中的元素一一对应,即from_array[b]等于 a,
例如‘d’在原数组中在索引9的位置第一次出现,‘f’则是在索引2的位置第一次出现;
第三个数组c,原数组映射到a中的索引值。即a[c]等于from_array;
第四个数组d,统计a中元素在原数组中出现的次数。
这里面b和c很有意思,能玩出很多花样来,有兴趣可以自己研究一下

回到原来的代码,这里主要的思想就是,把purpose_array中的元素合并到from_array的后面,合并之前需要清洗掉from_array中不存在的数据。这样对联合后的数组进行unique操作,不会影响到from_array部分的结果。我们可以对比看一下:

purpose_array = np.array(['b', 't', 'd', 'g', 'f', 'f', 'g', 'b', 'g', 'f', 'p', 'd', 'f', 'r', 'g', 'w', 't', 'd', 'e', 'b', 'e'])
from_array = np.array(['e', 'c', 'f', 'a', 'e', 'g', 'f', 'a', 'b', 'd', 'd', 'e'])
test = np.unique(from_array, return_index=True, return_inverse=True)
print(test)
p_idx = np.in1d(purpose_array, from_array)
union_array = np.hstack((from_array, purpose_array[p_idx]))
test2 = np.unique(union_array, return_index=True, return_inverse=True)
print(test2)

结果如下:

(array(['a', 'b', 'c', 'd', 'e', 'f', 'g'], dtype='<U1'), array([3, 8, 1, 9, 0, 2, 5], dtype=int64), array([4, 2, 5, 0, 4, 6, 5, 0, 1, 3, 3, 4], dtype=int64), array([2, 1, 1, 2, 3, 2, 1], dtype=int64))
(array(['a', 'b', 'c', 'd', 'e', 'f', 'g'], dtype='<U1'), array([3, 8, 1, 9, 0, 2, 5], dtype=int64), array([4, 2, 5, 0, 4, 6, 5, 0, 1, 3, 3, 4, 1, 3, 6, 5, 5, 6, 1, 6, 5, 3,
       5, 6, 3, 4, 1, 4], dtype=int64))

因为新的联合数组没有增加新的元素,也没有打乱from_array的顺序,所以得到的a、b数组还是不变。from_array[b]等于 a依然成立。而根据第三个数组的特性,a[c]等于原数组union_array,该数组包含from_array和purpose_array[p_idx]两部分,取后半部分就是purpose_array了。即c2 = c[len(from_array) :],a[c2]等于purpose_array[p_idx]。
from_array[b][c2]等于筛选过的purpose_array!目标达成,我们就是要找from_array到purpose_array的索引。
该索引值即b[c2]
测试一下:

a, b, c = test2
c2 = c[len(from_array):]
index = b[c2]
print(from_array[index])
print(purpose_array[p_idx])
['b' 'd' 'g' 'f' 'f' 'g' 'b' 'g' 'f' 'd' 'f' 'g' 'd' 'e' 'b' 'e']
['b' 'd' 'g' 'f' 'f' 'g' 'b' 'g' 'f' 'd' 'f' 'g' 'd' 'e' 'b' 'e']

结果一致!

贴上完整测试代码,目标数组长度为100000,数字范围0~9999
索引数组长度为20000,数字范围相同
以此来制造尽量复杂的情况,测试效率和结果是否正确

purpose_array = np.random.randint(0, 10000, 100000)
from_array = np.random.randint(0, 10000, 20000)
t1 = time.time()
purpose_idx_in_from1 = get_index_from_array(from_array, purpose_array)
t2 = time.time()
print(t2 - t1)
print(purpose_idx_in_from1)
idx = purpose_idx_in_from1[purpose_idx_in_from1 != -1]
a = from_array[idx]
b = purpose_array[purpose_idx_in_from1 != -1]
print((a == b).all(), '\n')
t1 = time.time()
purpose_idx_in_from2 = get_index_from_array2(from_array, purpose_array)
t2 = time.time()
print(t2 - t1)
print(purpose_idx_in_from2)
idx = purpose_idx_in_from2[purpose_idx_in_from2 != -1]
a = from_array[idx]
b = purpose_array[purpose_idx_in_from2 != -1]
print((a == b).all(), '\n')
t1 = time.time()
purpose_idx_in_from3 = get_index_from_array3(from_array, purpose_array)
t2 = time.time()
print(t2 - t1)
print(purpose_idx_in_from3)
idx = purpose_idx_in_from3[purpose_idx_in_from3 != -1]
a = from_array[idx]
b = purpose_array[purpose_idx_in_from3 != -1]
print((a == b).all(), '\n')
print((purpose_idx_in_from1 == purpose_idx_in_from2).all())
print((purpose_idx_in_from1 == purpose_idx_in_from3).all())

运行结果如下:

0.032914161682128906
[ 1820    -1 14529 ... 12893    -1 11580]
12.497856140136719
[ 1820    -1 14529 ... 12893    -1 11580]
12.462677478790283
[ 1820    -1 14529 ... 12893    -1 11580]

首先,三者结果测试正确,且三者完全一致
效率方面,传统方法则用了接近12.5秒(未使用多线程并行),map函数的方法让我感到意外,居然没有提高。而用我自己的方法,只花了0.033秒,提升了三四百倍的时间,果然是能不用for循环,千方百计也不要用。

PHP数组可以将许多其他不同变量类型的存入一个数组,并且存储容量可以根据与元素的增减自动调整。 根据数组下标提供的方式不同,可以分为索引数组和关联数组 索引数组索引为整数 关联数组以字符串为索引 数组的定义 1.直接为数组元素 2.使用array()函数声明数组 直接赋方法定义数组 $数组变量名[下标]=资料内容 $contact1[0]=1; $contact1[1]="高某"; $contact1[2] Python----数据分析-numpy.索引和切片 数组可以进行切片(分片)和索引操作,从而可以非常方便地提取数组的子集或者某个元素, 一维数组可以进行索引、分片、迭代等操作,和对列表的操作方式相似。 如图所示设b为0-20以内的一维偶数数组, b[2]—取出索引为2的元素(第三个元素) b[0:4]—取出索引为0-3的元素(第一至四个元素) 数组经过切片后并没有生成新的数组,得到的数组依然指向原数组,之所以不生成新的数组,是为了节约内存空间。 但为切片后的数组重新赋,原数组会改变,如图所示: 1.单个元素索引 这个是最简单的,因为无论是c,c++还是java,都允许这样。这也是我之前掌握的唯一一个numpy索引方法,可怜~。 y[0][1]#表示索引矩阵y的0行1列 2.行列索引 这次我们不是针对一个元素,我们要取出某些行或者某些列来。 y[[1,2 本文整理汇总了Pythonturtle.left方法的典型用法代码示例。如果您正苦于以下问题:Python turtle.left方法的具体用法?Python turtle.left怎么用?Python turtle.left使用的例子?那么恭喜您, 这里精选的方法代码示例或许可以为您提供帮助。您也可以进一步了解该方法所在模块turtle的用法示例。在下文一共展示了turtle.left方法的... a = [[1, 2, 3, 4, 5, 6, 7], [1, 2, 3, 4, 5, 6, 7]] a = np.array(a) b = [[7, 8, 9, 10, 11, 12, 13], [5, 8, 9, 10, 11, 12, 13]] b = np.array(b) print("a: ", a) print("b: ", b) print("b - a \n: ", b - a) print("(b - a)**2 \n: ", (b - a)*. 一个机器人位于一个m x n网格的左上角 (起始点在下图标记为 “Start” )。 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图标记为 “Finish” )。 求可能的路径个数。 在python列表查找某个元素索引的两种方法 1、方法一: 利用数组自身的特性 a.index(target), 其a是目标list,target是需要的下标对应的。代码如下: list1 = [1,7,2,4,5] print(a.index(4)) output: 这种方法仅仅能获取都第一个匹配的value的下标索引。 2、方法二:利用enumerate函数。可以输出所有的索引和对应...