在熊猫数据框中查找第一个和最后一个非 NaN 值

我有一个熊猫 DataFrame日期索引。有许多列,但许多列仅为时间序列的一部分填充。我希望找到非 NaN值的第一个和最后一个值的位置,以便提取日期,并查看特定列的时间序列有多长。

谁能告诉我怎样才能做这样的事?先谢谢你。

77887 次浏览

@ behzad. nori 的解决方案非常成功,分别使用 First _ valid_ indexLast _ valid_ index返回了第一个和最后一个非 NaN values

这里有一些有用的例子。

系列

s = pd.Series([np.NaN, 1, np.NaN, 3, np.NaN], index=list('abcde'))
s


a    NaN
b    1.0
c    NaN
d    3.0
e    NaN
dtype: float64


# first valid index
s.first_valid_index()
# 'b'


# first valid position
s.index.get_loc(s.first_valid_index())
# 1


# last valid index
s.last_valid_index()
# 'd'


# last valid position
s.index.get_loc(s.last_valid_index())
# 3

使用 notnaidxmax的替代解决方案:

# first valid index
s.notna().idxmax()
# 'b'


# last valid index
s.notna()[::-1].idxmax()
# 'd'

数据框架

df = pd.DataFrame({
'A': [np.NaN, 1, np.NaN, 3, np.NaN],
'B': [1, np.NaN, np.NaN, np.NaN, np.NaN]
})
df


A    B
0  NaN  1.0
1  1.0  NaN
2  NaN  NaN
3  3.0  NaN
4  NaN  NaN

没有在 DataFrames 上定义 (first|last)_valid_index,但是您可以使用 apply将它们应用于每一列。

# first valid index for each column
df.apply(pd.Series.first_valid_index)


A    1
B    0
dtype: int64


# last valid index for each column
df.apply(pd.Series.last_valid_index)


A    3
B    0
dtype: int64

和以前一样,您也可以使用 notnaidxmax

# first valid index
df.notna().idxmax()


A    1
B    0
dtype: int64


# last valid index
df.notna()[::-1].idxmax()


A    3
B    0
dtype: int64

一个基于 好了,好了的推荐和 Cs95的早期答案的方便功能。任何错误或误解都是我的。

import pandas as pd
import numpy as np


df = pd.DataFrame([["2022-01-01", np.nan, np.nan, 1], ["2022-01-02", 2, np.nan, 2], ["2022-01-03", 3, 3, 3], ["2022-01-04", 4, 4, 4], ["2022-01-05", np.nan, 5, 5]], columns=['date', 'A', 'B', 'C'])
df['date'] = pd.to_datetime(df['date'])


df
#        date    A    B    C
#0 2022-01-01  NaN  NaN  1.0
#1 2022-01-02  2.0  NaN  2.0
#2 2022-01-03  3.0  3.0  3.0
#3 2022-01-04  4.0  4.0  4.0
#4 2022-01-05  NaN  5.0  5.0

我们希望在 A 和 B 共有的最早日期开始,并在 A 和 B 共有的最晚日期结束(不管出于什么原因,我们不通过列 C 进行筛选)。

# filter data to minimum/maximum common available dates
def get_date_range(df, cols):
"""return a tuple of the earliest and latest valid data for all columns in the list"""
a,b = df[cols].apply(pd.Series.first_valid_index).max(), df[cols].apply(pd.Series.last_valid_index).min()
return (df.loc[a, 'date'], df.loc[b, 'date'])


a,b = get_date_range(df, cols=['A', 'B'])
a
#Timestamp('2022-01-03 00:00:00')
b
#Timestamp('2022-01-04 00:00:00')

现在过滤数据:

df.loc[(df.date >= a) & (df.date <= b)]
#        date    A    B    C
#2 2022-01-03  3.0  3.0  3
#3 2022-01-04  4.0  4.0  4