本问题已经有最佳答案,请猛点这里访问。
我有两个矩阵,分别对应于数据点(x,y1)和(x,y2):
x | y1
------------
0 | 0
1 | 1
2 | 2
3 | 3
4 | 4
5 | 5
x | y2
----------------
0.5 | 0.5
1.5 | 1.5
2.5 | 2.5
3.5 | 3.5
4.5 | 4.5
5.5 | 5.5
我想创建一个新的矩阵,将x值合并到单个列中,并在相应的y1,y2列中包含NaN s:
x | y1 | y2
-----------------------------
0 | 0 | NaN
0.5 | NaN | 0.5
1 | 0 | NaN
1.5 | NaN | 1.5
... | ... | ...
5 | 5 | NaN
5.5 | NaN | 5.5
是否有捷径可寻? 我是Python和NumPy的新手(来自MATLAB),我不确定如何开始。 (作为参考,我在MATLAB中对此的处理方式只是对使用array2table生成的两个表使用outerjoin。)
你有熊猫吗?
@c ??? s ???? 我可以安装它,更多的软件包没什么大不了的。
您将如何使用MATLAB进行此操作? 您将使用哪种结构?
@hpaulj编辑了问题,以将我的解决方案包含在MATLAB中。 id将我的两个矩阵转换为表,然后执行outerjoin。
使用纯numpy就像在MATLAB中仅使用matrix一样尴尬。 我可以使用结构化数组(和recfunctions.join)来近似它,它与MATLAB struct有一些相似之处(请参见stackoverflow.com/questions/47277436/)。 pandas更适合table之类的操作。
如果可以将数据加载到单独的pandas数据帧中,这将变得很简单。
df
x y1
0 0 0
1 1 1
2 2 2
3 3 3
4 4 4
5 5 5
df2
x y2
0 0.5 0.5
1 1.5 1.5
2 2.5 2.5
3 3.5 3.5
4 4.5 4.5
5 5.5 5.5
执行外部merge,并在x列上排序。
df = df.merge(df2, how='outer').sort_values('x')
df
x y1 y2
0 0 0 NaN
6 0.5 NaN 0.5
1 1 1 NaN
7 1.5 NaN 1.5
2 2 2 NaN
8 2.5 NaN 2.5
3 3 3 NaN
9 3.5 NaN 3.5
4 4 4 NaN
10 4.5 NaN 4.5
5 5 5 NaN
11 5.5 NaN 5.5
如果需要数组,请在结果上调用.values:
df.values
array([[0.0, 0.0, nan],
[0.5, nan, 0.5],
[1.0, 1.0, nan],
[1.5, nan, 1.5],
[2.0, 2.0, nan],
[2.5, nan, 2.5],
[3.0, 3.0, nan],
[3.5, nan, 3.5],
[4.0, 4.0, nan],
[4.5, nan, 4.5],
[5.0, 5.0, nan],
[5.5, nan, 5.5]], dtype=object)
真好 在这里使用熊猫很有意义。 基本上,您需要混合使用numpy数组和Python字典。
@EricDuminil谢谢。 对我来说,这似乎是最轻松的选择。 但是,我看到您的回答似乎令人印象深刻(我无法像您那样想出一个麻木的解决方案),并给了您好评:)
结构化数组方法(不完整):
输入特殊的函数库:
In [441]: import numpy.lib.recfunctions as rf
定义两个结构化数组
In [442]: A = np.zeros((6,),[('x',int),('y',int)])
糟糕,'x keys in B are float, so for consistency, let's make the A'也会浮动。不要不必要地混合浮点数和整数。
In [446]: A = np.zeros((6,),[('x',float),('y',int)])
In [447]: A['x']=np.arange(6)
In [448]: A['y']=np.arange(6)
In [449]: A
Out[449]:
array([( 0., 0), ( 1., 1), ( 2., 2), ( 3., 3), ( 4., 4), ( 5., 5)],
dtype=[('x', '
In [450]: B = np.zeros((6,),[('x',float),('z',float)])
In [451]: B['x']=np.linspace(.5,5.5,6)
In [452]: B['z']=np.linspace(.5,5.5,6)
In [453]: B
Out[453]:
array([( 0.5, 0.5), ( 1.5, 1.5), ( 2.5, 2.5), ( 3.5, 3.5),
( 4.5, 4.5), ( 5.5, 5.5)],
dtype=[('x', '
查看rf.join_by函数的文档:
In [454]: rf.join_by?
进行outer联接:
In [457]: rf.join_by('x',A,B,'outer')
Out[457]:
masked_array(data = [(0.0, 0, --) (0.5, --, 0.5) (1.0, 1, --) (1.5, --, 1.5) (2.0, 2, --)
(2.5, --, 2.5) (3.0, 3, --) (3.5, --, 3.5) (4.0, 4, --) (4.5, --, 4.5)
(5.0, 5, --) (5.5, --, 5.5)],
mask = [(False, False, True) (False, True, False) (False, False, True)
(False, True, False) (False, False, True) (False, True, False)
(False, False, True) (False, True, False) (False, False, True)
(False, True, False) (False, False, True) (False, True, False)],
fill_value = ( 1.00000000e+20, 999999, 1.00000000e+20),
dtype = [('x', '
结果是一个掩码数组,缺失值被掩码。
同样的事情,但是屏蔽关闭了:
In [460]: rf.join_by('x',A,B,'outer',usemask=False)
Out[460]:
array([( 0. , 0, 1.00000000e+20), ( 0.5, 999999, 5.00000000e-01),
( 1. , 1, 1.00000000e+20), ( 1.5, 999999, 1.50000000e+00),
( 2. , 2, 1.00000000e+20), ( 2.5, 999999, 2.50000000e+00),
( 3. , 3, 1.00000000e+20), ( 3.5, 999999, 3.50000000e+00),
( 4. , 4, 1.00000000e+20), ( 4.5, 999999, 4.50000000e+00),
( 5. , 5, 1.00000000e+20), ( 5.5, 999999, 5.50000000e+00)],
dtype=[('x', '
现在,我们可以清楚地看到填充值。必须有一种方法将1e20替换为np.nan。用nan替换999999会比较麻烦,因为np.nan是浮点值,而不是整数。
在join_by的幕后,可能首先是用join dtype创建一个blank数组,然后一个一个地填充字段。
这是使用普通numpy的尝试。它创建一个3列和a1 + a2一样多行的矩阵。它将a1和a2写入列中,并按第一个值对行进行排序。
请注意,仅当x值不相交时才有效:
import numpy as np
x = np.arange(6)
# array([0, 1, 2, 3, 4, 5])
a1 = np.vstack((x,x)).T
# array([[0, 0],
# [1, 1],
# [2, 2],
# [3, 3],
# [4, 4],
# [5, 5]])
a2 = a1 + 0.5
# array([[ 0.5, 0.5],
# [ 1.5, 1.5],
# [ 2.5, 2.5],
# [ 3.5, 3.5],
# [ 4.5, 4.5],
# [ 5.5, 5.5]])
m = np.empty((12, 3))
m[:] = np.nan
# array([[ nan, nan, nan],
# [ nan, nan, nan],
# [ nan, nan, nan],
# [ nan, nan, nan],
# [ nan, nan, nan],
# [ nan, nan, nan],
# [ nan, nan, nan],
# [ nan, nan, nan],
# [ nan, nan, nan],
# [ nan, nan, nan],
# [ nan, nan, nan],
# [ nan, nan, nan]])
m[:6, :2] = a1
# array([[ 0., 0., nan],
# [ 1., 1., nan],
# [ 2., 2., nan],
# [ 3., 3., nan],
# [ 4., 4., nan],
# [ 5., 5., nan],
# [ nan, nan, nan],
# [ nan, nan, nan],
# [ nan, nan, nan],
# [ nan, nan, nan],
# [ nan, nan, nan],
# [ nan, nan, nan]])
m[6:, ::2] = a2
# array([[ 0. , 0. , nan],
# [ 1. , 1. , nan],
# [ 2. , 2. , nan],
# [ 3. , 3. , nan],
# [ 4. , 4. , nan],
# [ 5. , 5. , nan],
# [ 0.5, nan, 0.5],
# [ 1.5, nan, 1.5],
# [ 2.5, nan, 2.5],
# [ 3.5, nan, 3.5],
# [ 4.5, nan, 4.5],
# [ 5.5, nan, 5.5]])
m[m[:,0].argsort()]
# array([[ 0. , 0. , nan],
# [ 0.5, nan, 0.5],
# [ 1. , 1. , nan],
# [ 1.5, nan, 1.5],
# [ 2. , 2. , nan],
# [ 2.5, nan, 2.5],
# [ 3. , 3. , nan],
# [ 3.5, nan, 3.5],
# [ 4. , 4. , nan],
# [ 4.5, nan, 4.5],
# [ 5. , 5. , nan],
# [ 5.5, nan, 5.5]])
在这里使用熊猫是正确的方法。
考虑到您可能不需要其他任何熊猫,这是标准的lib解决方案。
我将其分解为2个列表列表(假设元素的顺序很重要)。所以
xy1 = [[0,0],[1,1],......]
xy2 = [[0.5,0.5],[1.5,1.5],.......]
然后将这些列表合并到列表x中,在x [i] [1]或x [i] [2]位置交替添加" NaN",以补偿不存在的替代角色。每个x [i] [0]是字典元素的键,其值是上面列出的两个元素的列表。
finalx = {item[0]: item[1:] for item in x}
finalx = {0:[0, 'NaN'],0.5:[NaN,0.5],......]
希望这可以帮助。这更多的是方向,而不是解决方案。