查看 Pandas 中两列是否一对一的简单方法

Easy Way to See if Two Columns are One-to-One in Pandas

与 pandas 一起使用 Python 3+ 中的数据。似乎应该有一种简单的方法来检查两列是否具有一对一关系(无论列类型如何),但我正在努力想出最好的方法。

预期输出示例:

A    B     C
0    'a'   'apple'
1    'b'   'banana'
2    'c'   'apple'

A & B 是一对一的?真

A和C是一对一的?错误

B和C是一对一的?错误

嗯,你可以创建自己的函数来检查它:

def isOneToOne(df, col1, col2):
    first = df.groupby(col1)[col2].count().max()
    second = df.groupby(col2)[col1].count().max()
    return first + second == 2

isOneToOne(df, 'A', 'B')
#True
isOneToOne(df, 'A', 'C')
#False
isOneToOne(df, 'B', 'C')
#False

如果你的数据更像这样:

df = pd.DataFrame({'A': [0, 1, 2, 0],
                   'C': ["'apple'", "'banana'", "'apple'", "'apple'"],
                   'B': ["'a'", "'b'", "'c'", "'a'"]})
df
#   A    B         C
#0  0  'a'   'apple'
#1  1  'b'  'banana'
#2  2  'c'   'apple'
#3  0  'a'   'apple'

那么你可以使用:

def isOneToOne(df, col1, col2):
    first = df.drop_duplicates([col1, col2]).groupby(col1)[col2].count().max()
    second = df.drop_duplicates([col1, col2]).groupby(col2)[col1].count().max()
    return first + second == 2

解决这个问题的一种方法,

df['A to B']=df.groupby('B')['A'].transform(lambda x:x.nunique()==1)
df['A to C']=df.groupby('C')['A'].transform(lambda x:x.nunique()==1)
df['B to C']=df.groupby('C')['B'].transform(lambda x:x.nunique()==1)

输出:

   A  B       C  A to B  A to C  B to C
0  0  a   apple    True   False   False
1  1  b  banana    True    True    True
2  2  c   apple    True   False   False

逐列检查:

print (df['A to B']==True).all()
print (df['A to C']==True).all()
print (df['B to C']==True).all()

True
False
False
df.groupby(col1)[col2]\
  .apply(lambda x: x.nunique() == 1)\
  .all()

如果你想要正确或错误的答案,应该可以正常工作。

可视化具有离散/分类值的两列之间关系的一种好方法(如果您使用的是 Jupyter 笔记本)是:

df.groupby([col1, col2])\
  .apply(lambda x : x.count())\
  .iloc[:,0]\
  .unstack()\
  .fillna(0)

这个矩阵会告诉你两列中列值的对应关系。

在一对一关系的情况下,矩阵中每行只有一个非零值。

这是我的解决方案(只有两三行代码)检查任意数量的列以查看它们是否一对一匹配(允许重复匹配,请参阅下面的示例)。

cols = ['A', 'B'] # or any number of columns ['A', 'B', 'C']
res = df.groupby(cols).count()
uniqueness = [res.index.get_level_values(i).is_unique 
              for i in range(res.index.nlevels)]
all(uniqueness)

让我们把它变成一个函数并添加一些文档:

def is_one_to_one(df, cols):
    """Check whether any number of columns are one-to-one match.

    df: a pandas.DataFrame
    cols: must be a list of columns names

    Duplicated matches are allowed:
        a - 1
        b - 2
        b - 2
        c - 3
    (This two cols will return True)
    """
    if len(cols) == 1:
        return True
        # You can define you own rules for 1 column check, Or forbid it

    # MAIN THINGs: for 2 or more columns check!
    res = df.groupby(cols).count()
    # The count number info is actually bootless.
    # What maters here is the grouped *MultiIndex*
    # and its uniqueness in each level
    uniqueness = [res.index.get_level_values(i).is_unique
                  for i in range(res.index.nlevels)]
    return all(uniqueness)

通过使用此函数,您可以进行 one-to-one 匹配检查:

df = pd.DataFrame({'A': [0, 1, 2, 0],
                   'B': ["'a'", "'b'", "'c'", "'a'"],
                   'C': ["'apple'", "'banana'", "'apple'", "'apple'"],})

is_one_to_one(df, ['A', 'B'])
is_one_to_one(df, ['A', 'C'])
is_one_to_one(df, ['A', 'B', 'C'])
# Outputs:
# True
# False
# False
df.groupby('A').B.nunique().max()==1 #Output: True

df.groupby('B').C.nunique().max()==1 #Output: False

在 [groupby 列] 的每个值中,计算 [other 列] 中唯一值的数量,然后检查所有此类计数的最大值是否为一个