我有一个旧的遗留Fortran代码,将从Python调用。
在此代码中,数据数组是通过某种算法计算的。我简化了它:假设我们有10个元素要继续(在实际应用中它通常是10e + 6而不是10):
number_of_elements = 10
element_id_1 = [0, 1, 2, 1, 1, 2, 3, 0, 3, 0] # size = number_of_elements
element_id_2 = [0, 1, 2] # size = max(element_id_1)
然后按如下方式使用这些数组:
my_element = one_of_my_10_elements # does not matter where it comes from
my_element_position = elt_position_in_element_id_1 # does not matter how
id_1 = element_id_1[my_element_position]
if id_1 == 0:
id_2 = None
else:
id_2 = element_id_2[id_1-1]
modify(my_element, some_other_data[id_2])
管理这种关系的Pythonic / numpy方法是什么,即获得给定元素的id_2
?
我已经看过掩码阵列,但我还没有找到一种方法来使用它们进行这种配置。为元素实现一个类,它将在计算后存储id_2
并稍后提供它会让我想到与数组操作相比非常差的计算时间。我错了吗?
UPD。遗留代码中当前完成的更大范例:
import numpy as np
number_of_elements = 10
elements = np.arange(number_of_elements, dtype=int) # my elements IDs
# elements data
# where element_x[7] provides X value for element 7
# and element_n[7] provides N value for element 7
element_x = np.arange(number_of_elements, dtype=np.float)
element_n = np.arange(number_of_elements, dtype=np.int32)
# array defining subsets of elements
# where
# element_id_1[1] = element_id_1[3] = element_id_1[4] means elements 1, 3 and 4 have something in common
# and
# element_id_1[9] = 0 means element 9 does not belong to any group
element_id_1 = np.array([0, 1, 2, 1, 1, 2, 3, 0, 3, 0]) # size = number_of_elements
# array defining other data for each group of elements
# element_id_2[0] means elements of group 1 (elements 1, 3 and 4) have no data associated
# element_id_2[1] = 1 means elements of group 2 (elements 2 and 5) have data associated: other_x[element_id_2[1]-1] = 7.
# element_id_2[2] = 2 means elements of group 3 (elements 6 and 8) have data associated: other_x[element_id_2[1]-1] = 5.
element_id_2 = np.array([0, 1, 2]) # size = max(element_id_1)
other_x = np.array([7., 5.]) # size = max(element_id_2)
# work with elements
for my_element_position in elements:
id_1 = element_id_1[my_element_position]
if id_1 == 0:
print 'element %d, skipping'%(my_element_position)
continue
id_2 = element_id_2[id_1-1]
if id_2 > 0:
# use element_x[my_element_position], element_n[my_element_position] and other_x[id_2] to compute more data
print 'element %d, using other_x[%d] = %f'%(my_element_position, id_2, other_x[id_2-1])
else:
# use element_x[my_element_position] and element_n[my_element_position] to compute more data
print 'element %d, not using other_x'%(my_element_position)
我知道切片一个numpy数组比迭代它更快,我已经得到了以下切片:
elements_to_skip = np.where(element_id_1[:] == 0)[0]
for my_element_position in elements_to_skip:
print 'element %d, skipping'%(my_element_position)
elements_with_id1 = np.where(element_id_1[:] > 0)[0]
array1 = element_id_1[elements_with_id1]
array1 = element_id_2[array1-1]
array1 = np.where(array1[:] > 0)[0]
elements_with_data = elements_with_id1[array1]
id_2_array = element_id_2[element_id_1[elements_with_data]-1]
for my_element_position, id_2 in zip(elements_with_data, id_2_array):
print 'element %d, using other_x[%d] = %f'%(my_element_position, id_2, other_x[id_2-1])
elements_without_data = np.delete(elements, np.concatenate((elements_to_skip, elements_with_data)))
for my_element_position in elements_without_data:
print 'element %d, not using other_x'%(my_element_position)
这与上面的代码片段给出了相同的结果。你有没有办法让这个难以理解的代码变得更好?这种方法会比之前的代码片段更推荐吗?
答案 0 :(得分:2)
我不完全确定你的代码需要做什么,但我认为如果你正在使用numpy数组,你想做这样的事情:
number_of_elements = 10
element_id_1 = np.array([0, 1, 2, 1, 1, 2, 3, 0, 3, 0])
element_id_2 = np.array([np.NaN,0, 1, 2] )
# to get the "elemtn_id_1 th" elemnt from element_id_2
result=element_id_2[element_id_1]
我使用np.NaN而不是None如果您不想在结果中使用np.NaN,只需执行:
result[np.logical_not(np.isnan(result))]
编辑:根据您的示例代码,它只不过是我做的,您只需为案例0和1分配不同的other_x,然后从数组中提取您需要的任何内容:
element_id_1 = np.array([0, 1, 2, 1, 1, 2, 3, 0, 3, 0])
data=array([np.NaN,-1,7,5])
result=data[element_id_1]
print "skipping:"+str(np.where(np.isnan(result)))
print "using other data:"+str(np.where(nan_to_num(result)>0))
print "other data used:"+str(result[nan_to_num(result)>0])
print "not using other data:"+str(np.where(result==-1))
返回:
skipping:(array([0, 7, 9]),)
using other data:(array([2, 5, 6, 8]),)
other data used:[ 7. 7. 5. 5.]
not using other data:(array([1, 3, 4]),)
如果你不喜欢nans,你也可以通过在这种情况下分配-2来省略它们。
答案 1 :(得分:1)
如果我有类似的问题,我会选择hashMaps。 python中的dict
与大多数语言中的hashMap几乎相同
详细信息检查:Python dictionary implementation
如下所示:
id2_dict = {}
my_element = one_of_my_10_elements # does not matter where it comes from
my_element_position = elt_position_in_element_id_1 # does not matter how
id_1 = element_id_1[my_element_position]
if id_1 == 0:
id2_dict[id_1] = None
else:
id2_dict[id_1] = id2_dict[id_1-1]
考虑到数据的性质(整数),您可能希望使用list
,但如果您的id_1值很稀疏,那么您将浪费大量空间并且会减少 pythonic 方法。但是,如果您的id_1值跨越整数范围,并且在某些范围内密集,那么请使用列表并相应地处理索引。 list会为你节省散列部分,但会减少pythonic并且难以维护
tl; dr:如果id_1是密集且几乎跨越范围,请使用list
和id_1作为索引(使用一些索引移位),否则请使用(hashmap){{1 }和id_1为关键。