Pandas заменить последний элемент в группе, если NaN другим столбцом - PullRequest
4 голосов
/ 05 августа 2020

Я пытаюсь заменить последнюю строку в группе значением другого столбца, только если оно равно нулю. Я могу сделать обе эти части по отдельности, но не могу их объединить. У кого-нибудь есть идеи?

Это отдельные части:

# replace any NaN values with values from 'target'
df.loc[df['target'].isnull(),'target'] = df['value']

# replace last value in groupby with value from 'target'
df.loc[df.groupby('id').tail(1).index,'target'] = df['value']

Исходные данные:

    date        id      value       target
0   2020-08-07  id01    0.100775    NaN
1   2020-08-08  id01    0.215885    0.215885
2   2020-08-09  id01    0.012154    0.012154
3   2020-08-10  id01    0.374503    NaN
4   2020-08-07  id02    0.369707    0.369707
5   2020-08-08  id02    0.676743    0.676743
6   2020-08-09  id02    0.659521    0.659521
7   2020-08-10  id02    0.799071    NaN

Заменить столбец 'target' последней строкой в ​​groupby (' id ') с тем, что находится в' value ':

    date        id      value       target
0   2020-08-07  id01    0.100775    NaN
1   2020-08-08  id01    0.215885    0.215885
2   2020-08-09  id01    0.012154    0.012154
3   2020-08-10  id01    0.374503    0.374503
4   2020-08-07  id02    0.369707    0.369707
5   2020-08-08  id02    0.676743    0.676743
6   2020-08-09  id02    0.659521    0.659521
7   2020-08-10  id02    0.799071    0.799071

Ответы [ 4 ]

3 голосов
/ 06 августа 2020

fillna во всем столбце, но замаскируйте обратно на NaN, если он отсутствует, не последний для каждого «id».

m = df['target'].isnull() & df['id'].duplicated(keep='last')
df['target'] = df['target'].fillna(df['value']).mask(m)
         date    id     value    target
0  2020-08-07  id01  0.100775       NaN
1  2020-08-08  id01  0.215885  0.215885
2  2020-08-09  id01  0.012154  0.012154
3  2020-08-10  id01  0.374503  0.374503
4  2020-08-07  id02  0.369707  0.369707
5  2020-08-08  id02  0.676743  0.676743
6  2020-08-09  id02  0.659521  0.659521
7  2020-08-10  id02  0.799071  0.799071
3 голосов
/ 06 августа 2020

Так и должно быть. Добавлена ​​переменная tail для облегчения чтения синтаксиса:

tail = df.groupby('id').tail(1)
df.loc[tail.index,'target'] = df.loc[tail.index]['target'].fillna(tail.value) 

Вывод:

0 idx        date    id     value    target
1   0  2020-08-07  id01  0.100775       NaN
2   1  2020-08-08  id01  0.215885  0.215885
3   2  2020-08-09  id01  0.012154  0.012154
4   3  2020-08-10  id01  0.374503  0.374503
5   4  2020-08-07  id02  0.369707  0.369707
6   5  2020-08-08  id02  0.676743  0.676743
7   6  2020-08-09  id02  0.659521  0.659521
8   7  2020-08-10  id02  0.799071  0.799071
1 голос
/ 06 августа 2020

Найдите индекс последней цели внутри groupby(), а затем замените только нулевые значения, используя .combine_first()

indexes = df.groupby('id').tail(1).index
df.loc[indexes, 'target'] = df['target'].combine_first(df['value'])
#result
    date        id      value       target
0   2020-08-07  id01    0.100775    NaN
1   2020-08-08  id01    0.215885    0.215885
2   2020-08-09  id01    0.012154    0.012154
3   2020-08-10  id01    0.374503    0.374503
4   2020-08-07  id02    0.369707    0.369707
5   2020-08-08  id02    0.676743    0.676743
6   2020-08-09  id02    0.659521    0.659521
7   2020-08-10  id02    0.799071    0.799071
1 голос
/ 06 августа 2020

С comb_first вы избалованы выбором.

Первый вариант

Используйте .groupby() с nth(value)

m=df.groupby('id',as_index=False).nth(-1).index#mask each last value in the group
df.loc[m, 'target'] = df['target'].combine_first(df['value'])populate value

Второй вариант

Используйте combine_first с помощью метода доступа .iloc, чтобы получить последние значения в столбце target и value в одной строке groupby

     df.groupby('id').apply(lambda x:(x.iloc[-1:,3].combine_first(x.iloc[-1:,2])))\
.reset_index(level=0).combine_first(df)

Третий вариант

Выберите последний индекс в каждой группе. Заполните целевой столбец по мере необходимости и обновите df, используя comb_first

g=df.groupby('id').apply(lambda x:x.iloc[-1:]).reset_index(level=0, drop=True)
#df.loc[g, 'target'] = df['target'].combine_first(df['value'])
g.target=g.value
g.combine_first(df)



   date    id     value    target
0  2020-08-07  id01  0.100775       NaN
1  2020-08-08  id01  0.215885  0.215885
2  2020-08-09  id01  0.012154  0.012154
3  2020-08-10  id01  0.374503  0.374503
4  2020-08-07  id02  0.369707  0.369707
5  2020-08-08  id02  0.676743  0.676743
6  2020-08-09  id02  0.659521  0.659521
7  2020-08-10  id02  0.799071  0.799071
...