Обрезать конечные значения NaN в фрейме данных Python

Есть ли способ обрезать конечные NaN для каждого столбца в фрейме данных?

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

Пример данных выглядит следующим образом:

               1     2     3     4     5     6
2023-02-10   NaN   NaN   NaN  0.00  0.00   NaN
2023-02-13   NaN   NaN   NaN  0.02  0.02   NaN
2023-02-14   NaN   NaN   NaN  0.00  0.00   NaN
2023-02-15   NaN   NaN   NaN  0.01  0.01   NaN
2023-02-16   NaN   NaN   NaN -0.01 -0.01   NaN
2023-02-17   NaN   NaN   NaN -0.01 -0.01   NaN
2023-02-21   NaN   NaN   NaN -0.03 -0.03   NaN
2023-02-22   NaN   NaN   NaN  0.00  0.00   NaN
2023-02-23   NaN   NaN   NaN  0.00  0.00   NaN
2023-02-24   NaN -0.02   NaN -0.02 -0.02   NaN
2023-02-27   NaN  0.01   NaN  0.01  0.01   NaN
2023-02-28   NaN  0.03  0.03  0.00  0.00   NaN
2023-03-01   NaN -0.04 -0.04 -0.01 -0.01   NaN
2023-03-02   NaN  0.00  0.00  0.00  0.00   NaN
2023-03-03   NaN -0.01 -0.01  0.04  0.04   NaN
2023-03-06   NaN -0.02 -0.02  0.02  0.02   NaN
2023-03-07 -0.01 -0.01 -0.01 -0.01 -0.01   NaN
2023-03-08 -0.01 -0.01 -0.01   NaN  0.01   NaN
2023-03-09  0.00 -0.02 -0.02   NaN -0.01   NaN
2023-03-10 -0.03 -0.01 -0.01   NaN -0.01   NaN
2023-03-13  0.02 -0.03 -0.03   NaN  0.01   NaN
2023-03-14 -0.02 -0.02 -0.02   NaN  0.01   NaN
2023-03-15 -0.04  0.00  0.00   NaN  0.00   NaN
2023-03-16 -0.03  0.00  0.00   NaN  0.02   NaN
2023-03-17  0.01 -0.02 -0.02   NaN -0.01 -0.01
2023-03-20 -0.01 -0.01 -0.01   NaN  0.02  0.02
2023-03-21  0.03  0.01  0.01   NaN  0.01  0.01
2023-03-22  0.03 -0.05 -0.05   NaN -0.01 -0.01
2023-03-23 -0.01 -0.02 -0.02   NaN  0.01  0.01
2023-03-24  0.01  0.00  0.00   NaN  0.01  0.01

Мне нужен результат, который выглядит так:

               1     2     3     4     5     6
2023-02-10   NaN   NaN   NaN   NaN  0.00   NaN
2023-02-13   NaN   NaN   NaN   NaN  0.02   NaN
2023-02-14   NaN   NaN   NaN   NaN  0.00   NaN
2023-02-15   NaN   NaN   NaN   NaN  0.01   NaN
2023-02-16   NaN   NaN   NaN   NaN -0.01   NaN
2023-02-17   NaN   NaN   NaN   NaN -0.01   NaN
2023-02-21   NaN   NaN   NaN   NaN -0.03   NaN
2023-02-22   NaN   NaN   NaN   NaN  0.00   NaN
2023-02-23   NaN   NaN   NaN   NaN  0.00   NaN
2023-02-24   NaN -0.02   NaN   NaN -0.02   NaN
2023-02-27   NaN  0.01   NaN   NaN  0.01   NaN
2023-02-28   NaN  0.03  0.03   NaN  0.00   NaN
2023-03-01   NaN -0.04 -0.04   NaN -0.01   NaN
2023-03-02   NaN  0.00  0.00  0.00  0.00   NaN
2023-03-03   NaN -0.01 -0.01  0.02  0.04   NaN
2023-03-06   NaN -0.02 -0.02  0.00  0.02   NaN
2023-03-07 -0.01 -0.01 -0.01  0.01 -0.01   NaN
2023-03-08 -0.01 -0.01 -0.01 -0.01  0.01   NaN
2023-03-09  0.00 -0.02 -0.02 -0.01 -0.01   NaN
2023-03-10 -0.03 -0.01 -0.01 -0.03 -0.01   NaN
2023-03-13  0.02 -0.03 -0.03  0.00  0.01   NaN
2023-03-14 -0.02 -0.02 -0.02  0.00  0.01   NaN
2023-03-15 -0.04  0.00  0.00 -0.02  0.00   NaN
2023-03-16 -0.03  0.00  0.00  0.01  0.02   NaN
2023-03-17  0.01 -0.02 -0.02  0.00 -0.01 -0.01
2023-03-20 -0.01 -0.01 -0.01 -0.01  0.02  0.02
2023-03-21  0.03  0.01  0.01  0.00  0.01  0.01
2023-03-22  0.03 -0.05 -0.05  0.04 -0.01 -0.01
2023-03-23 -0.01 -0.02 -0.02  0.02  0.01  0.01
2023-03-24  0.01  0.00  0.00 -0.01  0.01  0.01

Не могли бы вы рассказать об этом подробнее? Похоже, вы делаете нечто большее, чем просто обрезку NaN из некоторых столбцов.

stefan_aus_hannover 16.05.2024 20:21

@stefan_aus_hannover, только что сдвинул четвертый столбец вниз до конца строк. Очевидно, нужно что-то в качестве пробела, поскольку в других столбцах есть записи, отличные от NaN, поэтому они заполняются заранее NaN.

Chris 16.05.2024 20:25

Просто для ясности: если у вас есть внутренние NaN, они должны остаться?

mozway 16.05.2024 20:30

@mozway, этого не должно случиться, но скажи да

Chris 16.05.2024 21:08

@Chris Крис, я предоставил два варианта решения этой проблемы: если у вас никогда не было внутренних NaN, trim_nans может быть быстрее;)

mozway 16.05.2024 21:11
Почему в 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 может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
5
51
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

IIUC, вы хотите удалить конечные NaN и «переместить» серию вниз, игнорируя индекс. dropna этого добиться не удастся.

Вы должны использовать пользовательскую функцию:

def trim_last_nan(s):
    # identify rows that are not trailing NaNs
    m = s[::-1].notna().cummax()[::-1]
    # select them, reindex
    return s[m].set_axis(s.index[-m.sum():])

out = df.apply(trim_last_nan)

Или:

def trim_last_nan(s):
    # shift by the number of trailing NaNs
    return s.shift(s[::-1].isna().cummin().sum())

Выход:

               1     2     3     4     5     6
2023-02-10   NaN   NaN   NaN   NaN  0.00   NaN
2023-02-13   NaN   NaN   NaN   NaN  0.02   NaN
2023-02-14   NaN   NaN   NaN   NaN  0.00   NaN
2023-02-15   NaN   NaN   NaN   NaN  0.01   NaN
2023-02-16   NaN   NaN   NaN   NaN -0.01   NaN
2023-02-17   NaN   NaN   NaN   NaN -0.01   NaN
2023-02-21   NaN   NaN   NaN   NaN -0.03   NaN
2023-02-22   NaN   NaN   NaN   NaN  0.00   NaN
2023-02-23   NaN   NaN   NaN   NaN  0.00   NaN
2023-02-24   NaN -0.02   NaN   NaN -0.02   NaN
2023-02-27   NaN  0.01   NaN   NaN  0.01   NaN
2023-02-28   NaN  0.03  0.03   NaN  0.00   NaN
2023-03-01   NaN -0.04 -0.04   NaN -0.01   NaN
2023-03-02   NaN  0.00  0.00  0.00  0.00   NaN
2023-03-03   NaN -0.01 -0.01  0.02  0.04   NaN
2023-03-06   NaN -0.02 -0.02  0.00  0.02   NaN
2023-03-07 -0.01 -0.01 -0.01  0.01 -0.01   NaN
2023-03-08 -0.01 -0.01 -0.01 -0.01  0.01   NaN
2023-03-09  0.00 -0.02 -0.02 -0.01 -0.01   NaN
2023-03-10 -0.03 -0.01 -0.01 -0.03 -0.01   NaN
2023-03-13  0.02 -0.03 -0.03  0.00  0.01   NaN
2023-03-14 -0.02 -0.02 -0.02  0.00  0.01   NaN
2023-03-15 -0.04  0.00  0.00 -0.02  0.00   NaN
2023-03-16 -0.03  0.00  0.00  0.01  0.02   NaN
2023-03-17  0.01 -0.02 -0.02  0.00 -0.01 -0.01
2023-03-20 -0.01 -0.01 -0.01 -0.01  0.02  0.02
2023-03-21  0.03  0.01  0.01  0.00  0.01  0.01
2023-03-22  0.03 -0.05 -0.05  0.04 -0.01 -0.01
2023-03-23 -0.01 -0.02 -0.02  0.02  0.01  0.01
2023-03-24  0.01  0.00  0.00 -0.01  0.01  0.01
как работает логика
           input  notna      m   new_index
2023-03-17 -0.02   True   True  2023-03-21
2023-03-20   NaN  False   True  2023-03-22
2023-03-21  0.01   True   True  2023-03-23
2023-03-22 -0.05   True   True  2023-03-24
2023-03-23   NaN  False  False         NaN
2023-03-24   NaN  False  False         NaN

примечание о внутренних NaN

Если у вас есть внутренние NaN, они останутся.

Например:

# input
               1     2     3     4     5     6
2023-03-17   NaN -0.02 -0.02  0.00 -0.01 -0.01
2023-03-20   NaN   NaN -0.01 -0.01  0.02  0.02
2023-03-21  0.03  0.01   NaN   NaN   NaN   NaN
2023-03-22  0.03 -0.05 -0.05   NaN -0.01 -0.01
2023-03-23 -0.01 -0.02 -0.02   NaN  0.01  0.01
2023-03-24  0.01   NaN  0.00   NaN  0.01   NaN

# output
               1     2     3     4     5     6
2023-03-17   NaN   NaN -0.02   NaN -0.01   NaN
2023-03-20   NaN -0.02 -0.01   NaN  0.02 -0.01
2023-03-21  0.03   NaN   NaN   NaN   NaN  0.02
2023-03-22  0.03  0.01 -0.05   NaN -0.01   NaN
2023-03-23 -0.01 -0.05 -0.02  0.00  0.01 -0.01
2023-03-24  0.01 -0.02  0.00 -0.01  0.01  0.01

Если вы хотите уменьшить все значения, используйте:

def trim_nans(s):
    m = s.notna()
    return s[m].set_axis(s.index[-m.sum():])

out = df.apply(trim_nans)

Выход:

               1     2     3     4     5     6
2023-03-20   NaN   NaN -0.02   NaN -0.01   NaN
2023-03-21  0.03 -0.02 -0.01   NaN  0.02 -0.01
2023-03-22  0.03  0.01 -0.05   NaN -0.01  0.02
2023-03-23 -0.01 -0.05 -0.02  0.00  0.01 -0.01
2023-03-24  0.01 -0.02  0.00 -0.01  0.01  0.01

И если вы хотите избежать удаления ведущих строк, состоящих из всех NaN:

out = df.apply(trim_nans).reindex(df.index)

               1     2     3     4     5     6
2023-03-17   NaN   NaN   NaN   NaN   NaN   NaN
2023-03-20   NaN   NaN -0.02   NaN -0.01   NaN
2023-03-21  0.03 -0.02 -0.01   NaN  0.02 -0.01
2023-03-22  0.03  0.01 -0.05   NaN -0.01  0.02
2023-03-23 -0.01 -0.05 -0.02  0.00  0.01 -0.01
2023-03-24  0.01 -0.02  0.00 -0.01  0.01  0.01

последнее допустимое значение

Если вам нужно только последнее допустимое значение, заполните и разрежьте с помощью iloc:

df.ffill().iloc[[-1]]

               1    2    3     4     5     6
2023-03-24  0.01  0.0  0.0 -0.01  0.01  0.01

спасибо за это... ради моего блага, что вы сделали, включив данные в свой пост, чтобы они правильно выстроились?

Chris 16.05.2024 20:26

@Chris, я использую print(df.to_string()), чтобы экспортировать его в правильном порядке. Я обновил ваш вопрос, сделав его более чистым.

mozway 16.05.2024 20:27

@mozway... потенциально более простой вариант - все, чего я действительно хочу добиться, это получить последнюю «действительную» строку. есть ли более прямой способ сделать это, чем все это?

Chris 16.05.2024 21:13

@Крис, в этом случае просто используй df.ffill().iloc[[-1]] ;)

mozway 16.05.2024 21:25

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