确定缺少值的数据帧是否是另一个数据帧的子集

2024-10-04 07:39:07 发布

您现在位置:Python中文网/ 问答频道 /正文

我有两只熊猫。它们共享相同的列。第一个较大,并且不包含缺失值,例如

import pandas as pd
import numpy as np

df_full = pd.DataFrame({
    "a": ["apple", "apple", "banana"],
    "b": [1, 2, 1]
})
        a  b
0   apple  1
1   apple  2
2  banana  1

第二行的行数较少,并且可能包含缺少的值

df_partial = pd.DataFrame({
    "a": ["apple", "apple"],
    "b": [np.nan, np.nan]
})
       a   b
0  apple NaN
1  apple NaN

我想确定是否可以通过从df_full中删除行和元素并重新排序行来获得df_partial。或者换一种方式,我们可以将df_partial中的每一行与df_full中的唯一行进行匹配,其中一行匹配的条件是其非缺失元素相等

因此,在上面的示例中,可以如上所述获得df_partial,因为我们可以将df_partial的前两行与df_full的前两行(以任意顺序)匹配

或者,数据帧

df_partial2 = pd.DataFrame({
    "a": ["banana"],
    "b": [2]
})
        a  b
0  banana  2

无法按说明获取,因为df_full中没有匹配的行

最后,还有一个稍微棘手的例子,dataframe

df_partial3 = pd.DataFrame({
    "a": ["apple", "apple", np.nan],
    "b": [1, 2, 2]
})
       a  b
0  apple  1
1  apple  2
2    NaN  2

无法按所述获取,因为即使可以将df_partial3中的每一行与df_full中的一行进行匹配,也无法从df_full中选择唯一的行来匹配df_partial3中的所有内容

其他一些考虑:

  • 这应该适用于任意数量的行/列
  • 您可以通过将所有可能的内射映射从df_partial行循环到df_full行来解决这个问题,但是如果可能的话,我想要更高效的东西

编辑:上面有一件事我没有说清楚。行的顺序并不重要。例如,数据帧

df_partial4 = pd.DataFrame({
    "a": ["apple", "apple"],
    "b": [np.nan, 1]
})
       a  b
0  apple  NaN
1  apple  1

即使我们必须将df_partial4中的第二行与df_full中的第一行匹配,并且将df_partial4中的第一行与df_full中的第二行匹配,也可以如上所述获得


Tags: import元素appledataframedfasnpnan
1条回答
网友
1楼 · 发布于 2024-10-04 07:39:07

感谢@user202729建议查找最大匹配问题。 这是我最终使用的解决方案

TL;医生:

import pandas as pd
import numpy as np
from scipy.sparse.csgraph import maximum_bipartite_matching
from scipy.sparse import csr_matrix

def is_match(df_partial, df_full):
    full = df_full.to_numpy()
    partial = df_partial.to_numpy()
    nans = df_partial.isna().to_numpy()
    matches = (full[:, np.newaxis, :] == partial) | nans
    adjacency_matrix = matches.all(axis=2)
    matching = maximum_bipartite_matching(csr_matrix(adjacency_matrix))
    return (matching >= 0).all()

下面,我将使用问题中给出的第一个示例更详细地介绍这些步骤

首先,我们创建一个矩阵,其中元素i,j是True,如果full_df的行i与partial_df的行j匹配,否则为false

full = df_full.to_numpy()
partial = df_partial.to_numpy()
nans = df_partial.isna().to_numpy()

# Use numpy broadcasting to get a pairwise row comparison
matches = (full[:, np.newaxis, :] == partial) | nans
adjacency_matrix = matches.all(axis=2)
[[ True  True]
 [ True  True]
 [False False]]

我们可以将其视为二部图的邻接矩阵,其中顶点是数据帧中的行,边位于匹配的行之间。我们想知道是否可以将df_partial中的每一行与df_full中的一行进行匹配。一个更一般的问题是,在df_partial中我们可以匹配的最大行数是多少

这个问题称为二部最大匹配问题,可以使用Hopcroft–Karp算法解决。据我所知,这是解决这个问题最有效的方法。在scipy中有一个实现

from scipy.sparse.csgraph import maximum_bipartite_matching
from scipy.sparse import csr_matrix


matching = maximum_bipartite_matching(csr_matrix(adjacency_matrix))
[0 1]

scipy函数maximum_bipartite_matching使用-1表示无法匹配的顶点,因此如果没有-1值,则df_partialdf_full的“子集”

is_subset = (matching >= 0).all()
True

相关问题 更多 >