接收3D或4D数组作为输入并在外部脚本中重塑为2D数组的函数
好的,我的问题比把三维或四维数组变成二维数组要具体一些。
我正在写一个脚本,用于处理三维或四维数组。
我想调用一个外部脚本中的函数,输入的唯一内容是一个三维数组。希望得到的输出是一个二维数组。
更详细地说,这个三维或四维数组的维度是 (x,y,t) 或 (x,y,z,t),其中 x、y 和 z 是空间维度,t 是时间。简单来说,这就是不稳定流动数据的存储方式。
现在我想把这个数组变成一个形状为 ([x*y*z, t]) 的二维数组。不过,这个过程只需要多维数组作为输入,我不想传递 x、y、z 和 t 的值。
有人能帮我写一个这样的函数吗?
类似于:
def frontend(data):
- 检查数据的形状
- 使用 len(data) 命令获取 x、y、z、t 的值
- 把数据变形为 ([x*y*z, t])
- 返回变形后的数据
更新:抱歉我没有说清楚。我遇到的问题正是关于形状的。例如,我在 x 方向有 100 步,在 y 方向有 50 步,在 z 方向有 10 步,在时间方向有 20 步。也就是说,这个数组的维度是 ([100,50,10,20])。现在,我需要把这个 ([100,50,10,20]) 的数组变成 ([50000,20]) 的数组。这可以通过普通的 'reshape' 命令来完成。现在的问题是,我只把数据数组传递给外部脚本中的函数,而我不知道它的维度。我需要找到数组的 X 维度、Y 维度、Z 维度和 t 维度,然后把这个四维数组变成一个二维数组,维度为 ([X*Y*Z, t])。最后,我需要得到这个二维数组作为输出。
2 个回答
感谢Pascal Rosin提供的解决方案,效果很好。
另外,我想出了另一个解决办法。
因为我在处理4维、3维和2维的数组,所以我在一个外部脚本中写了一个函数,然后把它导入到我的主脚本中使用。
我用ndarray.ndim来找出数组的维度,然后进行了合适的调整。
# Passing data as input
def frontend(data):
if data.ndim == 4:
data = data.reshape([data.shape[0]*data.shape[1]*data.shape[2],data.shape[3]])
return data
elif data.ndim == 3:
data = data.reshape([data.shape[0]*data.shape[1],data.shape[2]])
return data
elif data.ndim == 2:
return data
else:
text = 'unrecognized shape'
print str(text)
这个方法也非常有效。
更新:
问题的更新说明,函数 frontend()
只需要接收一个数组(Python 列表)。对于这种情况,这将是一个简化的解决方案:
def frontend(data):
return [reduce(lambda a, b: a*b, data[:-1]), data[-1]]
返回列表的第一个元素是通过将 data
中的所有元素相乘得到的,但不包括最后一个元素(data[:-1]
)。这可能是 [x, y]
或 [x, y, z]
。返回列表的第二个元素就是 data
的最后一个元素(data[-1]
)。在三维和四维的情况下,这个最后的元素就是 t
。
示例用法:
>>> frontend([100,50,10,20])
[50000, 20]
>>> frontend([100,50,20])
[5000, 20]
Python 3 的更新:
在 Python 3 中,不再有 reduce()
函数。如果不导入任何东西,你需要使用循环来实现:
def frontend(data):
product = 1
for elem in data[:-1]:
product = product * elem
return [product, data[-1]]
用法和上面一样:
>>> frontend([100,50,10,20])
[50000, 20]
之前处理元组列表的解决方案:
我不太确定你所说的“检查 data.shape”是什么意思。我理解为测试一个元素有多少维度。我展示了两个版本。第一个版本是检查 data
第一个元素中的值的数量,第二个版本则是将一个数据元素中的所有值相乘,但不包括最后一个,然后将最后一个值作为结果“二维”元素的第二个值:
# example data:
data_5d = [(1,2,3,4,5), (5,6,7,8,9)]
data_4d = [(1,2,3,4), (5,6,7,8)]
data_3d = [(1,2,3), (4,5,6)]
data_2d = [(1,2), (2,5)]
data_inconsistent = [(1,2,3,5), (8,9)]
# Version handling only 3D and 4D data:
# =====================================
def frontend(data):
#check data.shape:
# get number of dimensions by checking first element:
dimensions = len(data[0])
#optain values and reshape:
if dimensions == 4:
return [[x*y*z, t] for x, y, z, t in data]
elif dimensions == 3:
return [[x*y, t] for x, y, t in data]
else:
#handle error?
return []
print "frontend():"
print "5D: ", frontend(data_5d)
print "4D: ", frontend(data_4d)
print "3D: ", frontend(data_3d)
print "2D: ", frontend(data_2d)
# this would raise an exception:
#print frontend(data_inconsistent)
# General Version
# ===============
def frontendx(data):
return [[reduce(lambda a, b: a*b, elem[:-1]), elem[-1]] for elem in data]
print "\nfrontendx():"
print "5D: ", frontendx(data_5d)
print "4D: ", frontendx(data_4d)
print "3D: ", frontendx(data_3d)
print "2D: ", frontendx(data_2d)
print "?D: ", frontendx(data_inconsistent)
输出:
frontend():
5D: []
4D: [[6, 4], [210, 8]]
3D: [[2, 3], [20, 6]]
2D: []
frontendx():
5D: [[24, 5], [1680, 9]]
4D: [[6, 4], [210, 8]]
3D: [[2, 3], [20, 6]]
2D: [[1, 2], [2, 5]]
?D: [[6, 5], [8, 9]]