在DataFrame中计算每列的第一个非缺失值

10

我有一个类似于这样的DataFrame:

            1125400  5430095  1095751
2013-05-22   105.24      NaN  6507.58
2013-05-23   104.63      NaN  6393.86
2013-05-26   104.62      NaN  6521.54
2013-05-27   104.62      NaN  6609.31
2013-05-28   104.54    87.79  6640.24
2013-05-29   103.91    86.88  6577.39
2013-05-30   103.43    87.66  6516.55
2013-06-02   103.56    87.55  6559.43

我想计算每列的第一个非NaN值。

正如在Pandas DataFrame中定位第一个和最后一个非NaN值所指出的,可以使用first_valid_index。不幸的是,它返回第一个至少有一个元素不是NaN的行,而且无法按列工作。


我投票支持重新打开这个问题,因为标记的重复问题涉及逐行操作,而这个问题涉及逐列操作。这些问题和它们的答案实质上是不同的。 - William Miller
3个回答

14
你应该使用apply函数来高效地对每一列(默认)或每一行应用一个函数:
>>> first_valid_indices = df.apply(lambda series: series.first_valid_index())
>>> first_valid_indices
1125400   2013-05-22 00:00:00
5430095   2013-05-28 00:00:00
1095751   2013-05-22 00:00:00

first_valid_indices将成为一个序列,其中包含每个列的first_valid_index

您还可以在外部将lambda函数定义为普通函数:

def first_valid_index(series):
    return series.first_valid_index()

然后像这样调用apply:

df.apply(first_valid_index)

6
不必构建一个lambda函数或真正的函数,你可以使用Series类上的未绑定函数。df.apply(pd.Series.first_valid_index) - poulter7
以上代码仅提供每列第一个非空值的索引。它不完整,因为它没有提供如何在一次操作中使用实例的信息。 - rko

2
DataFrame.groupby().column.first()是一个内置函数,它返回列中第一个非空值,而last()则返回最后一个。如果您不希望为每个组获取第一个值,可以添加一个虚拟列1。然后使用groupby和first函数获取第一个非空值。
参考链接:http://pandas.pydata.org/pandas-docs/stable/generated/pandas.core.groupby.GroupBy.first.html
from Pandas import DataFrame

df = DataFrame({'a':[None,1,None],'b':[None,2,None]})
df['dummy'] = 1
df.groupby('dummy').first()
df.groupby('dummy').last()

这仅适用于数字类型。如果任何列是对象类型,则会得到None。 - nenetto

1
我假设你的意思是“访问”,而不是“计算”?
最简单的方法是使用 pd.Series.first_valid_index() 方法,可能需要在字典推导中使用:
values = {col : DF.loc[DF[col].first_valid_index(), col] for col in DF.columns}
values

需要澄清的是,pandas DataFrame 中的每一列都是一个 Series。因此,上面的代码与执行以下代码是相同的:

values = {}
for column in DF.columns:
    First_Non_Null_Index = DF[column].first_valid_index()
    values[column] = DF.loc[First_Non_Null_Index, column]

所以我的一行解决方案中的操作是针对每列进行的。也就是说,它不会像您在问题编辑中所建议的那样产生错误。如果没有达到预期效果,请告诉我。


这个方法可以用,但我希望有更简单的方法。 如果我使用 df.dropna(),它会删除所有至少有一个 NaN 的行。我可以对每一列进行逐个处理,但我希望有更简单的方法。 - yevgeny.bezman
哈哈哈,你不喜欢这个答案。好的,那看看更新后的答案吧! - Woody Pride
在我的解决方案中,它按列运行。每一列都是一个pandas Series,因此first_valid_index正好做你想要的事情...它正在查找数据帧的每一列中的第一个非空索引点,并给出该点的值。我认为你对问题的编辑是不正确的。 - Woody Pride
是的,您的解决方案逐列运行,每次在不同的系列上。first_valid_index对于系列的工作方式符合我的预期。在DataFrame上调用first_valid_index的工作方式如我在编辑中所描述的那样。 - yevgeny.bezman
那么实际上它确实做到了你想要的吗? - Woody Pride

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接