замена значений в столбце по условию
Имеем фрейм данных
import pandas as pd
import numpy as np
data = {'фрукт': ['груша','огурец','вишня', 'абрикос', 'груша','арбуз',
'груша','банан', 'груша', 'вишня','яблоко', 'груша',
'вишня', 'абрикос', 'груша', 'банан'],
'страна': ['россия','сша', 'россия','россия', 'франция','ЮАР',
'франция', 'россия', np.nan,'россия','андорра',
'франция', 'португалия', 'россия', np.nan, 'россия'],
'id': ['01','01','01','02','02','03','03','011', '011',
'011','011', '6', '6', '5', '5', '5'],
'месяц': ['март','январь','январь','март', 'март','март',
'октябрь','март', 'март', 'январь','март', 'март',
'январь', 'январь', 'ПРОПУЩЕНО', 'апрель']
}
df = pd.DataFrame(data, columns = ['фрукт','страна', 'id', 'месяц'])
Нужно провести замены некоторых значений в столбце месяц:
- если первые несколько (или только первая строка) строк подряд в группе
idимеют значениемесяц == март, а далее следует значение отличное отмарт, то на всю эту группуidнужно в колонкемесяцуказатьзначение, которое прерывает первые подряд идущие значениямарт - если все значение в группе
idв колонкемесяцимеют значениемарт, то значения в колонкемесяцне меняем - значение
ПРОПУЩЕНОигнорируем при првоерке исходного фрейма на наличие значения, котоорое прерывает первые подряд идущие (или одно значениемарт) значениямарт
Как это возможно сделать?
Ожидаемый результат:
Ответы (2 шт):
Автор решения: strawdog
→ Ссылка
Можно попробовать сделать так:
res = pd.DataFrame()
for i, g in df.groupby("id"):
g_ = g.copy()
if any(g["месяц"].str.contains("ПРОПУЩЕНО")):
g_["месяц"] = g_.iloc[0]["месяц"]
if any(g["месяц"].str.contains("март")) & (g["месяц"].nunique() >1):
g_["месяц"] = g_["месяц"].unique()[1]
res=pd.concat([res, g_])
res.sort_index(inplace=True)
res:
фрукт страна id месяц
0 груша россия 01 январь
1 огурец сша 01 январь
2 вишня россия 01 январь
3 абрикос россия 02 март
4 груша франция 02 март
5 арбуз ЮАР 03 октябрь
6 груша франция 03 октябрь
7 банан россия 011 январь
8 груша NaN 011 январь
9 вишня россия 011 январь
10 яблоко андорра 011 январь
11 груша франция 6 январь
12 вишня португалия 6 январь
13 абрикос россия 5 январь
14 груша NaN 5 январь
15 банан россия 5 январь
Автор решения: MaxU
→ Ссылка
Можно заменить все вхождения "март" на NaN и после этого сгруппировать по id и взять первое значение в группе, воспользовавшись методом GroupBy.first(). Специфика методов .first() и .last() в том, что они пытаются игнорировать значения NaN и как раз этим можно воспользоваться.
Пример:
df["res"] = (df
.assign(x=df["месяц"].replace("март", np.nan))
.groupby("id")
["x"]
.transform("first")
.fillna("март"))
результат:
In [28]: df
Out[28]:
фрукт страна id месяц res
0 груша россия 01 март январь
1 огурец сша 01 январь январь
2 вишня россия 01 январь январь
3 абрикос россия 02 март март
4 груша франция 02 март март
5 арбуз ЮАР 03 март октябрь
6 груша франция 03 октябрь октябрь
7 банан россия 011 март январь
8 груша NaN 011 март январь
9 вишня россия 011 январь январь
10 яблоко андорра 011 март январь
11 груша франция 6 март январь
12 вишня португалия 6 январь январь
13 абрикос россия 5 январь январь
14 груша NaN 5 ПРОПУЩЕНО январь
15 банан россия 5 апрель январь

