Python 确定缺少值的数据帧是否是另一个数据帧的子集
我有两只熊猫。它们共享相同的列。第一个较大,并且不包含缺失值,例如Python 确定缺少值的数据帧是否是另一个数据帧的子集,python,pandas,dataframe,Python,Pandas,Dataframe,我有两只熊猫。它们共享相同的列。第一个较大,并且不包含缺失值,例如 import pandas as pd import numpy as np df_full = pd.DataFrame({ "a": ["apple", "apple", "banana"], "b": [1, 2, 1] }) 第二行的行数较少,并且可能包含缺少的值 df_partial = pd.Dat
import pandas as pd
import numpy as np
df_full = pd.DataFrame({
"a": ["apple", "apple", "banana"],
"b": [1, 2, 1]
})
第二行的行数较少,并且可能包含缺少的值
df_partial = pd.DataFrame({
"a": ["apple", "apple"],
"b": [np.nan, np.nan]
})
我想确定是否可以通过从df_full
中删除行和元素并重新排序行来获得df_partial
。或者换一种方式,我们可以将df_partial
中的每一行匹配到df_full
中的唯一行,其中一行匹配的条件是其非缺失元素相等
因此,在上述示例中,可以如上所述获得df_partial
,因为我们可以将df_partial
的前两行与df_full
的前两行进行匹配(以任意顺序)
或者,数据帧
df_partial2 = pd.DataFrame({
"a": ["banana"],
"b": [2]
})
df_partial3 = pd.DataFrame({
"a": ["apple", "apple", np.nan],
"b": [1, 2, 2]
})
df_partial4 = pd.DataFrame({
"a": ["apple", "apple"],
"b": [np.nan, 1]
})
无法按说明获取,因为df_full
中没有匹配的行
最后,还有一个稍微棘手的例子,dataframe
df_partial2 = pd.DataFrame({
"a": ["banana"],
"b": [2]
})
df_partial3 = pd.DataFrame({
"a": ["apple", "apple", np.nan],
"b": [1, 2, 2]
})
df_partial4 = pd.DataFrame({
"a": ["apple", "apple"],
"b": [np.nan, 1]
})
无法按说明获取,因为即使您可以将df_partial3
中的每一行与df_full
中的一行相匹配,也无法从df_full
中选择唯一行来匹配df_partial3
中的所有内容
其他一些考虑:
- 这应该适用于任意数量的行/列
- 您可以通过将所有可能的内射映射从
行循环到df_partial
行来解决这个问题,但是如果可能的话,我想要更高效的东西df_full
df_partial2 = pd.DataFrame({
"a": ["banana"],
"b": [2]
})
df_partial3 = pd.DataFrame({
"a": ["apple", "apple", np.nan],
"b": [1, 2, 2]
})
df_partial4 = pd.DataFrame({
"a": ["apple", "apple"],
"b": [np.nan, 1]
})
即使我们必须将
df_partial4
中的第二行与df_full
中的第一行相匹配,并且将df_partial4
中的第一行与df_full中的第二行相匹配,也可以按所述获得。
is_subset = (matching >= 0).all()
这是我最终使用的解决方案
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\u df
的行i与partial\u 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)
我们可以将其视为二部图的邻接矩阵,其中顶点是数据帧中的行,边位于匹配的行之间。我们想知道是否可以将df_partial
中的每一行与df_full
中的一行进行匹配。一个更一般的问题是,df_partial
中我们可以在df_full
中匹配的最大行数是多少
is_subset = (matching >= 0).all()
这个问题称为二部最大匹配问题,可以使用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))
scipy函数,maximum_bipartite_matching
,使用-1表示无法匹配的顶点,因此如果没有-1值,则df_partial
是df_full
的“子集”
is_subset = (matching >= 0).all()
查找最大匹配问题。没有更简单的解决方案。谢谢@user202729,我已经更新了问题,以指示行可能会被重新排列。@user202729谢谢指向最大匹配问题的指针-看起来我的问题是二分匹配