接收3D或4D数组作为输入并在外部脚本中重塑为2D数组的函数

2 投票
2 回答
2011 浏览
提问于 2025-04-19 19:48

好的,我的问题比把三维或四维数组变成二维数组要具体一些。

我正在写一个脚本,用于处理三维或四维数组。

我想调用一个外部脚本中的函数,输入的唯一内容是一个三维数组。希望得到的输出是一个二维数组。

更详细地说,这个三维或四维数组的维度是 (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 个回答

0

感谢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)

这个方法也非常有效。

2

更新:

问题的更新说明,函数 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]]

撰写回答