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