Pandas- 在两个不共享索引的数据帧之间屏蔽 rows/columns

Pandas- masking rows/columns between two dataframes where indexes are not shared

问题

我有两个数据集,比方说,它们描述了海洋在特定深度和特定纬度的温度。数据集来自两个不同的模型,因此具有不同的分辨率,模型 1 的纬度分辨率更高,两个模型的深度维度级别不同。我已将两个数据集都转换为 pandas 数据帧,其中深度作为垂直索引,纬度作为列标签。我想屏蔽掉两个数据帧之间不共享的行(深度)和列(纬度),因为我会有所不同并且不想插入数据。我找到了如何屏蔽掉行和列中的某些值,但我想屏蔽掉整个行和列。

我在深度上使用 np.intersect1d 作为列表来查找模型之间不共享的深度,并且我使用条件语句创建了一个布尔列表,该语句为每个索引显示 True,其中的值是唯一的数据框。但是,我不确定如何使用它作为面具,或者即使我可以。 DataFrame.mask 表示“条件数组必须与自身形状相同”,但条件数组是一维的,而数据框是二维的。我不确定如何仅引用数据帧的索引来应用掩码。我觉得我走在正确的轨道上,但我不完全确定,因为我还是 pandas 的新手。 (我曾尝试搜索类似的问题,但 none 与我所看到的完全匹配。)

代码(简化的工作示例)

注意-这是在 Jupyter notebook 环境中编写的

import numpy as np
import pandas as pd

# Model 1 data
depthmod1 = [5, 10, 15, 20, 30, 50, 60, 80, 100]  #depth in meters
latmod1 = [50, 50.5, 51, 51.5, 52, 52.5, 53] #latitude in degrees north
tmpumod1 = np.random.randint(273,303,size=(len(depthmod1),len(latmod1))) #temperature
dfmod1 = pd.DataFrame(tmpumod1,index=depthmod1,columns=latmod1)
print(dfmod1)
     50.0  50.5  51.0  51.5  52.0  52.5  53.0
5     299   300   300   293   285   293   273
10    273   288   293   292   290   302   273
15    277   279   284   302   280   294   284
20    291   295   277   276   295   279   274
30    281   284   284   275   295   284   282
50    284   276   291   282   286   295   295
60    298   294   289   294   285   289   288
80    285   284   275   298   287   277   300
100   292   295   294   273   291   276   290
# Model 2 data
depthmod2  = [5, 10, 15, 25, 35, 50, 60, 100]
latmod2  = [50, 51, 52, 53]
tmpumod2  = np.random.randint(273,303,size=(len(depthmod2), len(latmod2)))
dfmod2 = pd.DataFrame(tmpumod2,index=depthmod2,columns=latmod2)
print(dfmod2)
      50   51   52   53
5    297  282  275  292
10   298  286  292  282
15   286  285  288  273
25   292  288  279  299
35   301  295  300  288
50   277  301  281  277
60   276  293  295  297
100  275  279  292  287
# Find shared depths
depthxsect = np.intersect1d(depthmod1, depthmod2)
print(depthxsect, depthxsect.shape)
Shared depths:  [  5  10  15  50  60 100] (6,)
# Boolean mask for model 1
depthmask = dfmod1.index.isin(depthxsect) == False
print("Bool showing where mod1 index is NOT in mod2: ", depthmask)
Bool showing where mod1 index is NOT in mod2:  [False False False  True  True False False  True False]
# Mask data
dfmod1masked = dfmod1.mask(depthmask1,np.nan)
print(dfmod1masked)
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-14-fedf013c2200> in <module>
----> 1 dfmod1masked = dfmod1.mask(depthmask1,np.nan)
      2 print(dfmod1masked)
[...]
ValueError: Array conditional must be same shape as self

问题

如何按索引屏蔽行,以便我只剩下 rows/indexes [ 5 10 15 50 60 100] 可用于两个数据帧?我将对列(纬度)进行类似的屏蔽,因此希望行的解决方案也适用于列。我也不想合并数据框。它们应该保持独立,除非为此需要合并。

depthxsect return 是您需要的 np.array 个索引。因此,您可以跳过创建布尔数组 depthmask,只需使用 .loc 将 np.array 传递给您的 datframe。如果您试图 保留 所有行,但仅保留 return NaN 其他索引上的值,则应使用 .mask

获得dfmod1depthxsect后,您可以简单地使用:

dfmod1.loc[depthxsect]

完整的可重现代码:

import pandas as pd
import numpy as np

# Model 1 data
depthmod1 = [5, 10, 15, 20, 30, 50, 60, 80, 100]  #depth in meters
latmod1 = [50, 50.5, 51, 51.5, 52, 52.5, 53] #latitude in degrees north
tmpumod1 = np.random.randint(273,303,size=(len(depthmod1),len(latmod1))) #temperature
dfmod1 = pd.DataFrame(tmpumod1,index=depthmod1,columns=latmod1)

depthmod2  = [5, 10, 15, 25, 35, 50, 60, 100]
latmod2  = [50, 51, 52, 53]
tmpumod2  = np.random.randint(273,303,size=(len(depthmod2), len(latmod2)))
dfmod2 = pd.DataFrame(tmpumod2,index=depthmod2,columns=latmod2)
depthxsect = np.intersect1d(depthmod1, depthmod2)
dfmod1.loc[depthxsect]
Out[2]: 
     50.0  50.5  51.0  51.5  52.0  52.5  53.0
5     284   291   280   287   297   286   277
10    294   279   302   283   284   298   291
15    278   296   286   298   279   275   286
50    284   281   297   290   302   299   280
60    290   301   302   298   283   286   287
100   285   283   297   287   289   282   283

我也包含了您正在尝试的方法。您必须在列上指定 mask。您在整个数据帧上执行此操作:

import pandas as pd
import numpy as np
# Model 1 data
depthmod1 = [5, 10, 15, 20, 30, 50, 60, 80, 100]  #depth in meters
latmod1 = [50, 50.5, 51, 51.5, 52, 52.5, 53] #latitude in degrees north
tmpumod1 = np.random.randint(273,303,size=(len(depthmod1),len(latmod1))) #temperature
dfmod1 = pd.DataFrame(tmpumod1,index=depthmod1,columns=latmod1)
dfmod1
depthmod2  = [5, 10, 15, 25, 35, 50, 60, 100]
latmod2  = [50, 51, 52, 53]
tmpumod2  = np.random.randint(273,303,size=(len(depthmod2), len(latmod2)))
dfmod2 = pd.DataFrame(tmpumod2,index=depthmod2,columns=latmod2)
depthxsect = np.intersect1d(depthmod1, depthmod2)
depthmask = dfmod1.index.isin(depthxsect) == False
for col in dfmod1.columns:
    dfmod1[col] = dfmod1[col].mask(depthmask, np.nan)
dfmod1
Out[3]: 
      50.0   50.5   51.0   51.5   52.0   52.5   53.0
5    289.0  274.0  297.0  274.0  277.0  278.0  277.0
10   282.0  280.0  277.0  302.0  297.0  289.0  278.0
15   300.0  282.0  297.0  297.0  300.0  279.0  291.0
20     NaN    NaN    NaN    NaN    NaN    NaN    NaN
30     NaN    NaN    NaN    NaN    NaN    NaN    NaN
50   285.0  297.0  292.0  301.0  296.0  289.0  291.0
60   295.0  299.0  278.0  295.0  299.0  293.0  277.0
80     NaN    NaN    NaN    NaN    NaN    NaN    NaN
100  292.0  293.0  289.0  291.0  289.0  276.0  286.0