为什么numpy.in1d()在我的例子中比在我的对象中运行得更快?

vptzau2j  于 2023-08-05  发布在  其他
关注(0)|答案(1)|浏览(77)

我必须在我的对象中处理两个表,如下所示:
表1:
| 产量| yield |
| --| ------------ |
| 一千| 1000 |
| 五百| 500 |
| 一百零四| 1024 |
其中code_material是一个10位数,其值不超过4 e +9
表2:
| 输入输出|编码材料|数量| qty |
| --|--|--| ------------ |
| 1000154210|输入|一百| 100 |
| 1123484257|输入|一百| 100 |
| 100010001| OUT| 50人| 50 |
我想做的是从表1中获取code_material,然后搜索表2的第一列以找到它的索引。并且对于TABLE 1中的'code_material'和TABLE 2中的'input/output'的一些值可以包括字符'-',如'-1000100001',指示它们是半成品。
我使用str作为两个cols的dtype,并使用np.in1d()来完成以下操作:

# read data from excel
TABLE1 = pd.read_excel(path1, 
                       dtype={'code_material':str, 'yield':float})
TABLE2 = pd.read_excel(path2,
                       dtype={'code_material':str, 'input/output':str,
                              'code_material':str, 'qty':float}

# convert to numpy array
_output = TABLE1['code_material'].to_numpy()
output = _output[~np.char.count(_output, '-')!=0]  # To remove half-finished

table2 = TABLE2.to_numpy()

# some operations to help me find those outputs, not casts.
_idx_notproduction = np.argwhere(table2[:, 2]=='IN')
idx_notproduction = np.argwhere(np.in1d(output, table2[_idx_notproduction, 1]))

# operating segment
j = 0
output = output.tolist()

while j < len(output):
  production = output[j]
  idx_in_table2 = np.argwhere(table2[:, 0] == production)
  # find those input casts
  idx_input = idx_in_table2[:-1]  # Sliced to prevent production from counting itself in.
  input = table2[idx_input, 1][~np.char.count(table2[idx_input, 1], '-')!=0]
  
  idx = np.inid(input, table2[:, 0])  #  here's the in1d that confuses me.

字符串
每次大约需要0.00423s。
但是当我尝试一个类似的示例时,我发现np.in1d()的运行速度比我在对象中的运行速度快了几乎一个数量级(每次大约0.000563s)。下面是我的例子:

arr1 = np.random.randint(1, 3e+9, (1, 5), dtype=np.int64)     # average of 5 codes per search
arr2 = np.random.randint(1, 3e+9, (1, 1170), dtype=np.int64)  # len(TABLE2)=1170 in object
arr1, arr2 = arr1.astype(str), arr2.astype(str)
cost = 0
for i in a:
  s = time.perf_counter()  #For the purpose of timing
  idx = np.in1d(arr1, arr2)
  cost += time.perf_counter() - s

print(cost/len(a))


请问是什么原因导致两个in1d()之间的速度差异如此之大?有没有可能使用这个原因来优化我在对象中的代码到这个速度?

vhipe2zx

vhipe2zx1#

以下是根据OP的要求从以前发布的评论中构建的答案:
问题当然是TABLE2.to_numpy()导致包含纯Python对象的Numpy数组。这样的对象是非常低效的(时间和内存空间)。您需要选择1个特定列,然后将其转换为Numpy数组。只有当所有数据框列都是相同类型时,您使用的操作才会相当快。此外,请注意,比较字符串是昂贵的,如@hpaulj所示。为了将“1000100001”与另一个字符串进行比较,Numpy将使用基本循环来比较10个字符中的每一个,而将整数与另一个进行比较只需要大约1条指令。
此外,请注意,Pandas总是将字符串存储在纯Python对象中。AFAIK,Numpy需要更新每个对象的引用计数,并关心锁定/释放GIL,更不用说需要内存间接,字符串通常使用Unicode存储,这往往更昂贵(例如额外的检查)。所有这些都比比较整数要昂贵得多。请重新考虑是否需要使用字符串。如果需要,您可以使用sentinel。负整数),甚至将它们Map到一组预定义的字符串。
最后但并非最不重要的是,请注意Pandas支持名为category的类型。当唯一字符串的数量明显小于行数时,它通常比普通字符串快得多。

相关问题