Есть ли способ обрезать конечные 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
@stefan_aus_hannover, только что сдвинул четвертый столбец вниз до конца строк. Очевидно, нужно что-то в качестве пробела, поскольку в других столбцах есть записи, отличные от NaN, поэтому они заполняются заранее NaN.
Просто для ясности: если у вас есть внутренние NaN, они должны остаться?
@mozway, этого не должно случиться, но скажи да
@Chris Крис, я предоставил два варианта решения этой проблемы: если у вас никогда не было внутренних NaN, trim_nans может быть быстрее;)






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, они останутся.
Например:
# 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, я использую print(df.to_string()), чтобы экспортировать его в правильном порядке. Я обновил ваш вопрос, сделав его более чистым.
@mozway... потенциально более простой вариант - все, чего я действительно хочу добиться, это получить последнюю «действительную» строку. есть ли более прямой способ сделать это, чем все это?
@Крис, в этом случае просто используй df.ffill().iloc[[-1]] ;)
Не могли бы вы рассказать об этом подробнее? Похоже, вы делаете нечто большее, чем просто обрезку NaN из некоторых столбцов.