Объединить строки в DataFrame pandas, игнорируя указанные значения и проверяя наличие конфликтов

Проблема

У меня есть набор фреймов данных, где каждая строка должна иметь уникальное значение идентификатора, но иногда импортированные данные содержат несколько строк с одним и тем же идентификатором. Я хочу сделать groupby операция или что-то подобное, которое проверяет каждую группу идентификаторов на наличие специальных символов, указывающих «нет данных», проверяет, что каждый столбец группы имеет ровно одно неспециальное значение (которое может повторяться в нескольких строках), а затем сворачивает группы идентификаторов в одну строку, значения столбцов которой являются либо уникальными неспециальными значениями столбцов из группы, либо специальными значениями в столбцах, где ни одна строка в группе не содержит данных.

Я хочу, чтобы код вызывал ошибку, если в столбце группы есть несколько разных неспециальных значений. Итак, если метка столбца идентификатора 'id' и специальные символы находятся в 'x?' тогда col2 ниже должно возникнуть исключение:

  id src col1 col2 col3
0  f   x    5    m    1
1  f   a    5    n    ?

Я собрал следующее решение, но я думаю, что должен быть способ попроще. Мой главный вопрос заключается в том, могу ли я сделать это с помощью большего количества нативного кода pandas вместо использования нескольких вспомогательных функций, как я сделал ниже.

Мой код

В настоящее время я выполняю это с помощью функции, называемой merge_rows который использует три вспомогательные функции:

  • get_nonspecial_values получает все неспециальные значения в столбце
  • check_column_consistency проверяет, имеет ли столбец ровно одно неспециальное значение
  • get_inconsistent_ids получает (надеюсь, пустой) набор значений идентификатора, строки которых конфликтуют друг с другом, например, со значением идентификатора 'f' выше.

Я думаю, что последние две строчки в get_inconsistent_ids и merge_rows вероятно, можно было бы выполнить с помощью встроенной операции pandas, которая затем сделала бы кучу кода, который я написал, ненужным, но я не могу понять, что это за операция (я также не уверен, что это строки для обратите внимание при пересмотре этого кода).

import pandas as pd

def get_nonspecial_values(series, specials):
    '''
    takes a series representing a column and returns all 
    values in the column that are not in specials
    '''
    counts = series.value_counts()
    return [v for v in counts.index if str(v) not in specials]

def check_column_consistency(series, specials):
    '''
    takes a series representing a column and returns True
    if there is exactly one value that is not in specials
    '''
    nonspecial = get_nonspecial_values(series, specials)
    if len(nonspecial) not in [1, 0]:
        return False
    else:
        return True

def get_inconsistent_ids(df, specials, id_column):
    '''
    takes a dataframe, special values, and a column label
    returns all ID values that represent a set of rows in which
    at least one column has multiple different nonspecial values
    '''
    where_nonunique_ids = df[id_column].duplicated(keep=False)
    if not any(where_nonunique_ids):
        return []
    else:
        rows_with_nonunique_ids = df.loc[where_nonunique_ids]
        check_group = lambda x: all(x.apply(check_column_consistency, args=(specials,)))
        where_ids_consistent = rows_with_nonunique_ids.groupby(id_column).apply(check_group)
        return [v for v in where_ids_consistent.index if not where_ids_consistent[v]]

def merge_rows(df, specials="", id_column=''):
    '''
    performs the merge operation described above
    '''
    inconsistent_ids = get_inconsistent_ids(df, specials=specials, id_column=id_column)
    if len(inconsistent_ids) > 0:
        raise ValueError('found the following ID values with inconsistent rows', inconsistent_ids)
    rows_with_nonunique_ids = df.loc[df[id_column].duplicated(keep=False)]
    unique_column_value = lambda x: (get_nonspecial_values(x, specials) or ['x'])[0]
    get_group_values = lambda x: x.apply(unique_column_value)
    values_by_id = rows_with_nonunique_ids.groupby(id_column).apply(get_group_values)
    return pd.DataFrame(data=values_by_id.values, columns=df.columns)

df = pd.DataFrame({'id' : ['a','b','c','c','d','d','d'],
                   'src': ['x','a','a','a','a','a','a'],
                   'col1':[ 5,  5, '?','?', 5,  5, 'x'],
                   'col2':['x','n','n','x','n','x','x'],
                   'col3':[ 1 , 3 ,'?', 9 ,'?', 8 ,'x']})

print(merge_rows(df, specials="x?", id_column='id'))

Приведенный выше код дает мне следующий вывод

  id src col1 col2 col3
0  c   a    x    n    9
1  d   a    5    n    8

0

Добавить комментарий

Ваш адрес email не будет опубликован.