如何检查一列的每个值是否正好映射到另一列中的一个值?

Cle*_*leb 3 python performance dataframe pandas

我有一个这样的数据框

import pandas as pd

df = pd.DataFrame({'A':list('bbcddee'), 'B': list('klmnnoi')})

   A  B
0  b  k
1  b  l
2  c  m
3  d  n
4  d  n
5  e  o
6  e  i
Run Code Online (Sandbox Code Playgroud)

我想从列中创建一个字典AB使用例如

dict(zip(df.A, df.B))
Run Code Online (Sandbox Code Playgroud)

在此之前,我想检查一下 in 中的每个值是否A仅映射到 中的一个值B;如果不是,则应抛出错误;上面的情况并非如此,因为b映射到kandl并且e映射到oand i

接近它的一种方法是:

df[df.groupby('A', sort=False)['B'].transform(lambda x: len(set(x))) > 1]
Run Code Online (Sandbox Code Playgroud)

返回

   A  B
0  b  k
1  b  l
5  e  o
6  e  i
Run Code Online (Sandbox Code Playgroud)

但是,这需要一个lambda可能会使其变慢的。有没有人看到加快速度的选项?

ALo*_*llz 5

你可以groupbynunique获得的“B”属于在“A”的每个唯一值的唯一值如何。

df.groupby('A').B.nunique()
#A
#b    2
#c    1
#d    1
#e    2
#Name: B, dtype: int64
Run Code Online (Sandbox Code Playgroud)

因此,您可以检查其中是否有超过 1 个映射:

df.groupby('A').B.nunique().gt(1).any()
#True
Run Code Online (Sandbox Code Playgroud)

以上在概念上与您提出的没有什么不同。但是,如果您能够使用已“优化”的内置 groupby 操作,而不是需要循环的慢速 lambda,则通常会获得重大的性能提升。我们可以看到,随着 DataFrame 变大,lambda 会变慢近 100 倍,这在开始需要几秒钟来计算时是一个大问题。

import perfplot
import pandas as pd
import numpy as np

def gb_lambda(df):
    return df.groupby('A')['B'].apply(lambda x: len(set(x))).gt(1)

def gb_nunique(df):
    return df.groupby('A').B.nunique().gt(1)

perfplot.show(
    setup=lambda n: pd.DataFrame({'A': np.random.randint(0, n//2, n), 
                                  'B': np.random.randint(0, n//2, n)}),
    kernels=[
        lambda df: gb_lambda(df),
        lambda df: gb_nunique(df),
    ],
    labels=['groupby with lambda', 'Groupby.nunique'],
    n_range=[2 ** k for k in range(2,18)],
    equality_check=np.allclose,  
    xlabel='~len(df)'
)
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明

  • 效果也很好(已投票)。要获取包含所有重复项的数据帧,可以执行“df[df.groupby('A').B.transform('nunique') > 1]”。 (2认同)