繁体   English   中英

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

[英]How to check whether each value of one column maps to exactly one value in another column?

我有一个像这样的 dataframe

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

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

dict(zip(df.A, df.B))

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

一种接近它的方法是:

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

返回

   A  B
0  b  k
1  b  l
5  e  o
6  e  i

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

您可以使用groupby进行nunique ,以获取“B”中有多少唯一值属于“A”中的每个唯一值。

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

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

df.groupby('A').B.nunique().gt(1).any()
#True

以上在概念上与您提出的没有什么不同。 但是,如果您能够使用已“优化”的内置 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)'
)

在此处输入图像描述

您可以使用pd.Series.duplicateddf.duplicated并将keep参数设置为False

df[df.A.duplicated(keep=False) & (~df.duplicated(keep=False))]

   A  B
0  b  k
1  b  l
5  e  o
6  e  i

细节

df.A.duplicated(keep=False) # To eliminate `A` values occur only once

0     True
1     True
2    False # ----> `c` which has no duplicates 
3     True
4     True
5     True
6     True
Name: A, dtype: bool

~df.duplicated(keep=False) # Capture values having different mapping
0     True
1     True
2     True
3    False # ----> d n
4    False # ----> d n
5     True
6     True
dtype: bool

让我们尝试filter

df.groupby('A').filter(lambda x : x['B'].nunique()>1)
   A  B
0  b  k
1  b  l
5  e  o
6  e  i

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM