Pandas ffill limit groups of nan меньше чем limit only

Я хочу переслать некоторые значения в мой фрейм данных pandas с ограничением. Однако предел должен заполнять только группы наноразмеров, в которых количество непрерывных нанометров меньше или равно пределу. Вот пример,

Создайте df с недостающими данными,

import numpy as np
import pandas as pd

df = pd.DataFrame(
        {'val': [1, 1, np.nan, np.nan, 2, 3, np.nan, np.nan, np.nan, np.nan, 1, 1]}
)

print(df)

    val
0     1.0
1     1.0
2     NaN
3     NaN
4     2.0
5     3.0
6     NaN
7     NaN
8     NaN
9     NaN
10    1.0
11    1.0

Теперь, если мы заполним его, все наны будут заполнены на 2 шага вперед,

print(df.ffill(limit=2))

    val
0     1.0
1     1.0
2     1.0
3     1.0
4     2.0
5     3.0
6     3.0 #
7     3.0 #
8     NaN
9     NaN
10    1.0
11    1.0

Те чтения (выше) с # fill, когда я этого не хочу. Я бы хотел получить следующее,

print(df.ffill(limit=2, dont_fill_any_nan_gaps_bigger_than_limit=True))

    val
0     1.0
1     1.0
2     1.0
3     1.0
4     2.0
5     3.0
6     NaN # 
7     NaN #
8     NaN 
9     NaN 
10    1.0
11    1.0

Конечно, это не обязательно должен быть единственный параметр в ffill, но что-то с таким же эффектом.

Сразу понял, что наполовину закончил титул. Я добавил название, но, пожалуйста, предложите лучший. Не знал, как это описать ...

Little Bobby Tables 20.04.2018 14:17
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
2
1
814
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Вы можете безоговорочно использовать ffill при условии, что вы не заполните его после использования pd.Series.mask / pd.Series.where / np.where.

v = df.value.isna()  # df.value.isnull()
df = df.ffill(limit=2).mask(
     v.groupby(v.ne(v.shift()).cumsum()).transform('size').gt(2)
)

    value
0     1.0
1     1.0
2     1.0
3     1.0
4     2.0
5     3.0
6     NaN
7     NaN
8     NaN
9     NaN
10    1.0
11    1.0

Я видел, как был представлен isna. Рекомендуется ли он вместо isnull?

Little Bobby Tables 20.04.2018 14:18

@josh Нет, это разные имена, но оба делают одно и то же.

cs95 20.04.2018 14:20

Извините, они делают то же самое. Я хотел спросить, рекомендуется ли использовать isna для уточнения / является ли isnull устаревшим?

Little Bobby Tables 20.04.2018 14:40

@josh Для переносимости используйте isnull, isna, я думаю, был введен только в версии 0.21. На данный момент ни один из них не является устаревшим.

cs95 20.04.2018 14:43

Создайте маску для фильтрации всех строк с NaN с размером больше, чем 2 на groupby и transformsize, и примените ffill только для отфильтрованных строк с условием инвертирования по ~:

a = df['value'].isna()
a = a.ne(a.shift()).cumsum()
m = (a.groupby(a).transform('size') > 2)
df[~m] = df[~m].ffill(limit=2)
print (df)
    value
0     1.0
1     1.0
2     1.0
3     1.0
4     2.0
5     3.0
6     NaN
7     NaN
8     NaN
9     NaN
10    1.0
11    1.0
Ответ принят как подходящий

Я черпал вдохновение в обоих отличных ответах, а также в этом отвечать от jezral до моего предыдущего вопрос, чтобы применить это ко всему DataFrame.

Я сделал это для того, чтобы обработать весь DataFrame за один раз и чтобы каждый столбец ffill содержал недостающие значения в своих соответствующих столбцах (с моим дополнительным ограничением).

Настройте DataFrame,

df = pd.DataFrame(
    {'val1': [1, 1, np.nan, np.nan, 2, 3, np.nan, np.nan, np.nan, np.nan, 1, 1],
     'val2': [1, 2, np.nan, np.nan, 2, 4, 4, np.nan, np.nan, np.nan, np.nan, 2]}
)

print(df)

    val1    val2
0   1.0     1.0
1   1.0     2.0
2   NaN     NaN
3   NaN     NaN
4   2.0     2.0
5   3.0     4.0
6   NaN #   4.0
7   NaN #   NaN #
8   NaN #   NaN #
9   NaN #   NaN #
10  1.0     NaN #
11  1.0     2.0

Теперь сделайте mask и ffill,

mask_df = (
    df.isnull()
      .groupby([df.notnull().all(axis=1).cumsum()])
      .rank(method='max') - 1
).gt(2)

df = df.ffill().mask(mask_df)
print(df)

    val1    val2
0   1.0     1.0
1   1.0     2.0
2   1.0     2.0
3   1.0     2.0
4   2.0     2.0
5   3.0     4.0
6   NaN #   4.0
7   NaN #   NaN #
8   NaN #   NaN #
9   NaN #   NaN #
10  1.0     NaN #
11  1.0     2.0

Объяснение

Мы groupby, используя кумулятивную сумму значений, отличных от nan. Это означает, что значения nan сгруппированы вместе. Если мы возьмем максимальное значение rank из них, мы получим длину последовательности nan + 1. Теперь мы просто используем функцию mask, как показано cᴏʟᴅsᴘᴇᴇᴅ's отвечать.

Если установить df.iloc[9,1] = 23, это перестает работать, если вы хотите обрабатывать каждый столбец df отдельно. Мой текущий обходной путь - определить функцию маски def masker(df, limit): return (df.isna().groupby([df.notna().cumsum()]).rank(method='max') - 1).gt(limit) и применить эту функцию к столбцам: mask_df = df_ext.apply(masker, axis=0, args=(limit,)). Я думаю, это довольно медленно для больших фреймов данных. Есть ли способ сделать это напрямую без подачи заявки?

JE_Muc 12.11.2018 18:14

@ Scotty1 - Я не могу понять, почему df.iloc[9,1] = 23 ломает это. Может быть, лучше лечить причину, а не симптомы, но я посмотрю на это.

Little Bobby Tables 13.11.2018 10:55

@josh [df.notnull().all(axis=1).cumsum()] с axis=1 в качестве аргумента groupby рассматривает только строки, которые все являются nan. Но я не смог применить к этому векторизованный подход, у меня сработало только применение. К сожалению, использование этого метода маскирования с применением на фреймах данных среднего размера ужасно медленное. Но честно говоря: я плохо разбираюсь в groupby и т. д., Поэтому я совершенно уверен, что есть лучший подход.

JE_Muc 13.11.2018 11:01

Я просто остановил свой тестовый прогон на df формы (2600000, 80) через 45 минут. Должен быть способ векторизовать это ...

JE_Muc 13.11.2018 11:28

@ Scotty1- извини, теперь я слежу. Это будет сложно, но это действительно хороший вопрос, поэтому стоит создать для него новый пост.

Little Bobby Tables 13.11.2018 14:00

@josh Хорошо, завтра я отвечу на следующий вопрос и опубликую ссылку здесь, в комментариях.

JE_Muc 13.11.2018 14:04

Другие вопросы по теме