用三个一维的numpy数组填充一个二维的numpy数组

8

有没有一种高效的方法可以创建一个二维数组,其中包含来自未排序坐标点的值(即不是所有经度和/或纬度都按升序或降序排列),而无需使用循环?

示例数据

lats = np.array([45.5,45.5,45.5,65.3,65.3,65.3,43.2,43.2,43.2,65.3])
lons = np.array([102.5,5.5,116.2,102.5,5.5,116.2,102.5,5.5,116.2,100])
vals = np.array([3,4,5,6,7,7,9,1,0,4])

示例输出
每列代表一个唯一的经度(102.5、5.5、116.2和100),每行代表一个唯一的纬度(45.5、65.3和43.2)。

([ 3, 4, 5, NaN],
 [ 6, 7, 7, 4],
 [ 9, 1, 0, NaN])

尽管如此,这并不是那么直接的,因为我不一定知道每个经度或纬度有多少个重复项,这决定了数组的形状。

更新:
我在提问时将数据排列错误。现在我已经排列好了,所以它们都是唯一的对,并且有一个额外的数据点来演示当NaN存在时数据应该如何排列。


输出数组的大小由什么决定?是latslons中非重复值的数量吗? - danodonovan
没错... 我想是这样的 :) - ryanjdillon
1
你能用言语解释一下是哪些规格使得示例输出成为所期望的答案吗?当100不是“vals”中的值时,什么逻辑表明应该将100放入输出中?为什么是这样? - unutbu
那只是我的错误,抱歉。应该是一个我没有放在值数组中的附加值。现在正在更正。 - ryanjdillon
3个回答

5
您发布的示例非常不合理,也没有任何合理的方法来指定缺失的数据。我猜测您可能正在处理类似于以下内容的东西:
>>> lats = np.array([43.2, 43.2, 43.2, 45.5, 45.5, 45.5, 65.3, 65.3, 65.3])
>>> lons = np.array([5.5, 102.5, 116.2, 5.5, 102.5, 116.2, 5.5, 102.5, 116.2])
>>> vals = np.array([3, 4, 5, 6, 7, 7, 9, 1, 0])

vals[j] 的值来自纬度 lats[j] 和经度 lons[j],但数据可能会混乱,例如:

>>> indices = np.arange(9)
>>> np.random.shuffle(indices)
>>> lats = lats[indices]
>>> lons = lons[indices]
>>> vals = vals[indices]
>>> lats
array([ 45.5,  43.2,  65.3,  45.5,  43.2,  65.3,  45.5,  65.3,  43.2])
>>> lons
array([   5.5,  116.2,  102.5,  116.2,    5.5,  116.2,  102.5,    5.5,  102.5])
>>> vals
array([6, 5, 1, 7, 3, 0, 7, 9, 4])

您可以按照以下方式将此安排为数组:
>>> lat_vals, lat_idx = np.unique(lats, return_inverse=True)
>>> lon_vals, lon_idx = np.unique(lons, return_inverse=True)
>>> vals_array = np.empty(lat_vals.shape + lon_vals.shape)
>>> vals_array.fill(np.nan) # or whatever yor desired missing data flag is
>>> vals_array[lat_idx, lon_idx] = vals
>>> vals_array
array([[ 3.,  4.,  5.],
       [ 6.,  7.,  7.],
       [ 9.,  1.,  0.]])

谢谢Jaime。这也是一个很好的答案,非常有帮助。对于糟糕的示例,我表示歉意。有时候我发现很难在不添加不必要的内容混淆事情的情况下完善我的问题。 - ryanjdillon
我想我明白了哪些地方不太清楚。lat/lon/value数据应该是唯一的对,并且它们在排序上都是一致的;尽管如此,没有一个列表是严格升序或降序排列的。我已经正确地重新排序了这些内容(使它们唯一),并添加了一个值来演示当NaN存在时输出应该是什么样子的。感谢您的帮助! - ryanjdillon
@shootingstars 您编辑后的示例输入仍与您期望的输出不一致。但我现在更加确信,我上面提出的方法是您想要的。在您的示例输入上尝试它(在vals数组中添加一个100之后!),看看您得到了什么,理解为什么它与您期望的不同,我认为您最终会意识到上述方法是正确的方式。 - Jaime
没错,这个方法非常好用,而且似乎比使用视图更清晰。输出数组中的“100”和“vals”数组中缺少新值是我在打字时犯的错误。对于我的误解和打字错误,我很抱歉,再次感谢您的帮助!这真是启发性的。 - ryanjdillon
谢谢你,Jaime!我花了几个小时才找到这样的解决办法! - balu
我正在使用这个技巧将(x,y,z)格式的点转换为可以用matplotlib.pyplot.contour绘制的东西,但我觉得vals_array似乎是转置的。因此,contour(lat_vals, lon_vals, vals_array)无法绘制,而contour(lat_vals, lon_vals, vals_array.transpose())可以。显然,我正在处理经度和纬度具有不同数量唯一值的情况。[[我对这种行为感到非常困惑,可能我犯了一些错误]] - Rho Phi

1
如果您正在创建一个二维数组,那么所有的数组都必须具有相同数量的点。如果是这样,您可以简单地执行以下操作:
out = np.vstack((lats, lons, vals))

编辑

认为这可能是你需要的,至少与你的问题相符 :)

xsize = len(np.unique(lats))
ysize = len(np.unique(lons))

然后,如果您的数据表现得非常良好

out = [vals[i] for i, (x, y) in enumerate(zip(lats, lons))]
out = np.asarray(out).reshape((xsize, ysize))

我觉得我的措辞不太好,但是我希望最终得到一个维度为(len(lats),len(lon))的数组,其中仅包含它们各自坐标的值。 - ryanjdillon
但是 latslons 不是整数值 - 所以它们不会完美地适合大小为 (max(lats), max(lon)) 的网格中,我错过了什么吗? - danodonovan
抱歉,这些是列表,因此它将是列表的长度(即元素的整数数量),但我刚意识到我真正想要的是len(lats)/重复lats的数量等。请参见我对问题的更新。 - ryanjdillon

1
import numpy as np

lats = np.array([45.5,45.5,45.5,65.3,65.3,65.3,43.2,43.2,43.2,65.3])
lons = np.array([102.5,5.5,116.2,102.5,5.5,116.2,102.5,5.5,116.2,100])
vals = np.array([3,4,5,6,7,7,9,1,0,4])


def unique_order(seq): 
    # http://www.peterbe.com/plog/uniqifiers-benchmark (Dave Kirby)
    # Order preserving
    seen = set()
    return [x for x in seq if x not in seen and not seen.add(x)]

unique_lats, idx_lats = np.unique(lats, return_inverse=True)
unique_lons, idx_lons = np.unique(lons, return_inverse=True)
perm_lats = np.argsort(unique_order(lats))
perm_lons = np.argsort(unique_order(lons))

result = np.empty((len(unique_lats), len(unique_lons)))
result.fill(np.nan)
result[perm_lats[idx_lats], perm_lons[idx_lons]] = vals
print(result)

产生
[[  3.   4.   5.  nan]
 [  6.   7.   7.   4.]
 [  9.   1.   0.  nan]]

这看起来很不错,但我一直收到“ValueError:新数组的总大小必须保持不变”的错误。我猜我在某个地方混淆了什么,因为这个和danodonovan的答案都非常简单明了。 - ryanjdillon
另外,你对输出是正确的。我遇到的错误是在我使用实际数据集/脚本时出现的,而不是在示例中。 - ryanjdillon
1
ValueError 表示 len(vals) 不等于 len(np.unique(lats)) * len(np.unique(lons))。如果 len(vals) 太长,您想要截断 vals 吗?如果 len(vals) 太短,您想要用 0 填充数组的其余部分吗?还有很多其他可能性... - unutbu
啊...我发现我的纬度比经度少一些独特的值(所有值都是独特的)。我想我应该用缺失值来填充剩下的部分,例如NaN或-9999,或者其他合适的值。 - ryanjdillon
你是否有填充空缺的建议方法?似乎 reshape 不支持直接填充。 - ryanjdillon
经过第二次仔细查看,似乎这并不像我想的那样运作。我已经更新了我的问题进行解释。再次感谢帮助! - ryanjdillon

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接