Простой способ узнать, являются ли две колонны один в один в Пандах - PullRequest
0 голосов
/ 01 июня 2018

Работа с данными в Python 3+ с пандами.Кажется, должен быть простой способ проверить, имеют ли два столбца отношение один к одному (независимо от типа столбца), но я изо всех сил пытаюсь придумать лучший способ сделать это.

Пример ожидаемого результата:

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

A & B один на один?ИСТИНА

A & C один на один?FALSE

B & C один на один?FALSE

Ответы [ 4 ]

0 голосов
/ 03 июля 2019

Вот мое решение (только две или три строки кодов), чтобы проверить любое количество столбцов , чтобы увидеть, совпадают ли они один к одному (дублированные совпадения разрешены, см. Пример ниже).

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)

Используя эту функцию, вы можете выполнить проверку соответствия один на один:

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
0 голосов
/ 01 июня 2018

один способ решить эту проблему,

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
0 голосов
/ 30 ноября 2018
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)

Эта матрица покажет вам соответствие между значениями столбцов в двух столбцах.

В случае отношения один к одному будет только одно ненулевое значениеза строку в матрице.

0 голосов
/ 01 июня 2018

Ну, вы можете создать свою собственную функцию для проверки:

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
...