Не работает отбор значений по min
Выделяю минимальные значения каждого периода из столбца Input. Это 'min'.
Должно получатся минимальное число, но выходит 0.
Как сделать правильно?
from itertools import product
import xlrd
df = pd.read_csv('1111.csv')
def first(s):
return s.loc[(s!=0).idxmax()] # с изменением на idxmin()] не работает
col = 'Input'
mask = (df[col].ne(0) & df[col].shift(-1).eq(0))
tmp = df.groupby(mask.shift().fillna(0).cumsum())[col].agg([first, 'last', 'min'])
new_cols = ["<first>", "<last>", "<min>"]
df = df.assign(**dict(product(new_cols, [""])))
df.loc[mask, new_cols] = tmp.iloc[:mask.sum()].values
Пример данных:
Input
7 0
8 0
9 0
10 0
11 0
12 0
13 0
14 0
15 0
16 22.65
17 22.65
18 22.66
19 22.65
20 22.65
21 22.65
22 22.66
23 22.65
24 22.65
25 22.65
26 22.64
27 22.64
28 22.65
29 0
30 0
31 0
32 0
Что должно быть:
Input <first> <last> <min>
7 0
8 0
9 0
10 0
11 0
12 0
13 0
14 0
15 0
16 22.65
17 22.65
18 22.66
19 22.65
20 22.65
21 22.65
22 22.66
23 22.65
24 22.65
25 22.65
26 22.64
27 22.64
28 22.65 22.65 22.65 22.64
29 0
30 0
31 0
32 0
33 0
34 0
35 0
36 22.64 22.64 22.64 22.64
37 0
38 0
39 0
40 0
Файл данных.
Пример CSV - в нем уже есть first, last, min, но min пустой - т.к. этот код его не вычислил.
Ответы (3 шт):
Автор решения: MarianD
→ Ссылка
Ваша проблема в том, что ваша функция
def first(s):
return s.loc[(s!=0).idxmax()] # с изменением на idxmin()] не работает
не работает правильно ни с .idxmax()!
Посмотрите:
(s!=0)— это серия из логижеских значений, т. е.True/False,- когда в этой серии будут присутствовать обе эти значения, то минимальным будет
Falseи максимальным будетTrue, - в вашем случае она начинается с
False, значит,(s!=0).idxmax()будет0, - пусть она будет например
False,False,True,True,True,False, - тогда
(s!=0).idxmax()будет2, другими словами, индекс первого ненулевого значения серииs, что вы вероятно не хотели.
Автор решения: MaxU
→ Ссылка
можно написать собственную функцию для нахождения минимума, которая будет игнорировать нулевые значения:
def mmin(ser):
return ser.loc[ser != 0].min()
дальше пользуемся практически тем же кодом, что и у вас в вопросе:
mask = (df[col].ne(0) & df[col].shift(-1).eq(0))
tmp = df.groupby(mask.shift().fillna(0).cumsum())[col].agg([first, "last", mmin])
# NOTE: --------------------------------------------------------------> ^^^^
new_cols = ["<first>", "<last>", "<min>"]
df = df.assign(**dict(product(new_cols, [""])))
df.loc[mask, new_cols] = tmp.iloc[:mask.sum()].values
результат:
In [39]: df
Out[39]:
Input <first> <last> <min>
7 0.00
8 0.00
9 0.00
10 0.00
11 0.00
12 0.00
13 0.00
14 0.00
15 0.00
16 22.65
17 22.65
18 22.66
19 22.65
20 22.65
21 22.65
22 22.66
23 22.65
24 22.65
25 22.65
26 22.64
27 22.64
28 22.65 22.65 22.65 22.64
29 0.00
30 0.00
31 0.00
32 0.00
Автор решения: MarianD
→ Ссылка
def applyfunc(df):
funcs = ["first", "last", "min", "max"]
n = len(df)
s = n * [""]
for func in funcs:
colname = f"<{func}>"
if func == "first":
val = df.Input.iloc[0]
elif func == "last":
val = df.Input.iloc[-1]
else:
val = getattr(df.Input, func)()
s[n-1] = val if val != 0 else ""
df[colname] = s
return df
key = df.Input.apply("sign").abs().diff().abs().fillna(0).cumsum()
df.groupby(key).apply(applyfunc)