#python #pandas #dataframe #nan
#python #pandas #фрейм данных #nan
Вопрос:
У меня есть фрейм данных pandas со столбцом с именем ‘A_col’, и я хотел бы создать новый столбец с именем ‘A_col_fill’, который заменит NaN в ‘A_col’ на минимальное значение непосредственно перед ним, если оно есть. Пример вывода выглядит следующим образом.
A_col A_col_fill
0 NaN NaN
1 NaN NaN
2 NaN NaN
3 NaN NaN
4 NaN NaN
5 NaN NaN
6 NaN NaN
7 -0.3400 -0.3400
8 NaN -0.3400
9 NaN -0.3400
10 -0.1900 -0.1900
11 NaN -0.1900
12 -0.3700 -0.3700
13 -0.4100 -0.4100
14 -0.3300 -0.3300
15 NaN -0.4100
16 NaN -0.4100
17 NaN -0.4100
18 NaN -0.4100
19 NaN -0.4100
20 -1.6500 -1.6500
21 -1.8000 -1.8000
22 -1.5300 -1.5300
23 -1.3500 -1.3500
24 NaN -1.8000
25 -0.1900 -0.1900
26 -0.1400 -0.1400
28 -0.2100 -0.2100
Похоже, что функция ‘fillna’ фрейма данных не работает с регистром, как я могу это реализовать, любой фрагмент кода высоко ценится!
Комментарии:
1. Не могли бы вы добавить некоторую информацию о правилах, по которым он должен выбирать? похоже, что правило состоит в том, чтобы выбрать минимум (предыдущий непрерывный блок [не NaN]), это правильно?
2. Не должно ли значение с индексом 11 быть -0.3400? Самый простой способ реализовать это — поместить этот столбец в список, а затем выполнить итерацию по этому списку, отслеживая текущий минимум.
3. точно! Мне нравится выбирать минимум предыдущего непрерывного блока для замены NaN
4. @MachineLearner, индекс 11 равен -0.1900
Ответ №1:
Это решение будет заполнять nan с помощью следующего минимального значения последнего «острова» смежных строк, содержащих значения. Он должен быть более точным и производительным, чем другие предлагаемые решения (за счет усложнения):
- создайте столбец с номером группы для каждого «острова» смежных значений или nan
- получите минимальное значение для каждой группы; перенаправьте заполнение строк nan предыдущим минимальным значением
- заполните исходный столбец новым минимальным значением для группы
код:
df["group_col"] = np.cumsum(df["A_col"].isna() != df["A_col"].isna().shift())
df["group_min"] = df.groupby("group_col").A_col.transform(min).ffill()
df["output"] = df["A_col"].fillna(df.group_min)
Результат:
A_col A_col_fill group_col group_min output
0 NaN NaN 1 NaN NaN
1 NaN NaN 1 NaN NaN
2 NaN NaN 1 NaN NaN
3 NaN NaN 1 NaN NaN
4 NaN NaN 1 NaN NaN
5 NaN NaN 1 NaN NaN
6 NaN NaN 1 NaN NaN
7 -0.34 -0.34 2 -0.34 -0.34
8 NaN -0.34 3 -0.34 -0.34
9 NaN -0.34 3 -0.34 -0.34
10 -0.19 -0.19 4 -0.19 -0.19
11 NaN -0.19 5 -0.19 -0.19
12 -0.37 -0.37 6 -0.41 -0.37
13 -0.41 -0.41 6 -0.41 -0.41
14 -0.33 -0.33 6 -0.41 -0.33
15 NaN -0.41 7 -0.41 -0.41
16 NaN -0.41 7 -0.41 -0.41
17 NaN -0.41 7 -0.41 -0.41
18 NaN -0.41 7 -0.41 -0.41
19 NaN -0.41 7 -0.41 -0.41
20 -1.65 -1.65 8 -1.80 -1.65
21 -1.80 -1.80 8 -1.80 -1.80
22 -1.53 -1.53 8 -1.80 -1.53
23 -1.35 -1.35 8 -1.80 -1.35
24 NaN -1.80 9 -1.80 -1.80
25 -0.19 -0.19 10 -0.21 -0.19
26 -0.14 -0.14 10 -0.21 -0.14
28 -0.21 -0.21 10 -0.21 -0.21
Решение занимает миллисекунды для 1 м строки df на моей машине:
df = pd.DataFrame(np.random.random(size=100000), columns=["A_col"])
df.loc[df.sample(frac=0.6).index, "A_col"] = np.nan
# code from above
df["group_col"] = np.cumsum(df["A_col"].isna() != df["A_col"].isna().shift())
df["group_min"] = df.groupby("group_col").A_col.transform(min).ffill()
df["output"] = df["A_col"].fillna(df.group_min)
Комментарии:
1. Чувак, хороший, четкий ответ! это именно то, что я ищу. Спасибо
Ответ №2:
p['A_col'].fillna(np.inf).replace(np.inf,p['A_col'].ffill().cummin())
вывод:
0 NaN
1 NaN
2 NaN
3 NaN
4 NaN
5 NaN
6 NaN
7 -0.34
8 -0.34
9 -0.34
10 -0.19
11 -0.34
12 -0.37
13 -0.41
14 -0.33
15 -0.41
16 -0.41
17 -0.41
18 -0.41
19 -0.41
20 -1.65
21 -1.80
22 -1.53
23 -1.35
24 -1.80
25 -0.19
26 -0.14
28 -0.21
Комментарии:
1. эй, это будет иметь ужасную временную сложность больше, чем O (n ^ 2). Иногда эффективен простой код wring. Утилиты Pandas / python не работают. Это просто итерация строки по всем строкам с сохранением минимума
2. серьезно? вы не видели cummin, это операция O (n)
3. Возможно, я что-то упускаю, но предполагаемый результат OP для индекса 11 должен был быть -0,19, а не -0,34?
4. @anon01 попробуйте проверить время выполнения вашего кода на некоторых фиктивных данных. Я запустил 10 тысяч строк, а время обработки вашего кода составляет 19 секунд. Я запустил линейный цикл, сохраняя минимум, а время обработки составляет 42 мс. Вы должны прочитать о временной сложности 🙂
5. Спасибо! Даже этот фрагмент кода очень близок к тому, что мне нужно, кроме значения в индексе 11, которое должно быть -0,19
Ответ №3:
Простое решение, просто выполните итерацию по столбцу и сохраните минимальное время и заполните значение Nan
def fill_min(df):
minx = np.inf
ans = []
for val in df['A_Col']:
if np.isnan(val):
ans.append(val if np.isinf(minx) else minx)
else:
minx = min(minx, val)
ans.append(val)
return ans
ИСПОЛЬЗУЙТЕ:
df['A_col_fill'] = fill_min(df)