Объединить парные строки после группового панды, дать значение NaN, если ID не встречался дважды в df - PullRequest
2 голосов
/ 21 июня 2019

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

  • Чтобы выбрать несовпадающие строки и пары совпадающих строк, я могу использовать groupby в столбце идентификатора.
  • Теперь для каждой группы я хочу взять несколько столбцов из второй (парной) строки, переименовать их и скопировать в первую строку. Затем я могу отбросить все вторые строки и вернуть один кадр данных, содержащий все измененные первые строки (для каждой группы).
  • Там, где нет второго ряда (несовпадающего) - можно поставить NaN на его место.

Чтобы проиллюстрировать это, см. Таблицу ниже id=1 и 3 - сопоставленная пара, но id=2 не соответствует:

entity id partner value
A      1  B       200
B      1  A       300
A      2  B       600
B      3  C       350
C      3  B       200

Полученное преобразование должно оставить мне следующее:

entity id partner entity_value partner_value
A      1  B       200          300
A      2  B       600          NaN
B      3  C       350          200

Меня сбивает с толку то, как найти общий способ получения соответствия partner_value из строки 2, скопированного в строку 1 после группировки, таким образом, который также работает, когда нет соответствующего идентификатора.

Ответы [ 3 ]

3 голосов
/ 22 июня 2019

Решение (это было сложно):

dfg = df.groupby('id', sort=False)

# Create 'entity','id','partner','entity_value' from the first row...
df2 = dfg['entity','id','partner','value'].first().rename(columns={'value': 'entity_value'})

# Now insert 'partner_value' from those groups that have a second row...
df2['partner_value'] = nan
df2['partner_value'] = dfg['value'].nth(n=1)

   entity  id partner  entity_value  partner_value
id                                                
1       A   1       B           200          300.0
2       A   2       B           600            NaN
3       B   3       C           350          200.0

Это было сложно получить работу.Короткий ответ заключается в том, что хотя pd.groupby(...).agg(...) в принципе позволяет вам указать список кортежей (column, aggregate_function), и вы можете затем связать их в переименование , это не сработает, поскольку мыпытаясь выполнить две отдельные агрегатные операции в столбце value и переименовать оба их результата (вы получите pandas.core.base.SpecificationError: Function names must be unique, found multiple named value).

Другие сложности:

  • Мы не можем напрямую использовать groupby.nth(n), что на первый взгляд кажется полезным, за исключением того, что это только для DataFrame, а не для серии, подобной df['value'], а также без вывода сообщений группы, у которых нет nэлемент, а не то, что мы хотим.(Но он сохраняет индекс, поэтому мы можем использовать его, сначала инициализируя столбец как все-NaN, а затем выборочно вставляя в этот столбец, как указано выше).
  • В любом случае синтаксис pd.groupby.agg() выиграл 'даже не позволяя вам вызывать nth(), просто передавая 'nth' в качестве имени agg_func, так как nth() отсутствует аргумент n;вам нужно было бы объявить лямбду.
  • Я попытался определить следующую функцию second_else_nan для использования внутри agg(), как указано выше, но после долгих попыток я не смог заставить это работать несколько разпричины, только одна из которых заключается в том, что вы не можете выполнить две операции в одном столбце:

Код:

def second_else_nan(v):
    if v.size == 2:
        return v[1]
    else:
        return pd.np.nan

(т. е. эквивалент в списке dict.get(key, default) встроенный)

1 голос
/ 21 июня 2019

Я бы так и сделал.Сначала получите первое значение:

df_grouped = df.reset_index().groupby('id').agg("first")

Затем извлеките дублирующиеся значения и вставьте их:

df_grouped["partner_value"] = df.groupby("id")["value"].agg("last")

Единственное, что у вас есть повторяющееся значение, если оно недублируется (вместо NaN).

0 голосов
/ 21 июня 2019

Как насчет этого?

grouped = df.groupby("id")
first_values = grouped.agg("first")
sums = grouped.agg("sum")
first_values["partner_value"] = sums["value"] - first_values["value"]
first_values["partner_value"].replace(0, np.nan, inplace=True)

transformed_df = first_values.copy()

Сгруппировать данные по идентификатору, взять первую строку, взять сумму столбца «значение» для каждой группы, из этого вычитания «значение» изПервый ряд.Затем замените 0 в результирующем столбце на np.nan (при этом предполагается, что данные из столбца 'value' никогда не равны 0)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...