在一个列中找到第一个和/或最后一个非NaN值的索引

7
我正在处理井孔的地下测量数据,每种测量类型覆盖不同深度范围。在这种情况下,深度被用作索引。
我需要找到每种测量类型第一个和/或最后一个数据(非NaN值)出现的深度(索引)。
获取数据框的第一行或最后一行的深度(索引)很容易:df.index[0]df.index[-1]。关键是找到任何给定列的第一个或最后一个非NaN出现的索引。
df = pd.DataFrame([[500, np.NaN, np.NaN,     25],
                   [501, np.NaN, np.NaN,     27],
                   [502, np.NaN,     33,     24],
                   [503,      4,     32,     18],
                   [504,     12,     45,      5],
                   [505,      8,     38, np.NaN]])
df.columns = ['Depth','x1','x2','x3']
df.set_index('Depth')

enter image description here

理想的解决方案应该为x1的第一次出现产生深度(索引)为503,x2的第一次出现产生深度为502,并且x3的最后一次出现产生深度为504。

1
但是,对于 'x3',您如何决定它需要是最后一个有效索引,而不是第一个 - ALollz
每个变量都需要知道第一个或最后一个有效索引。诀窍在于,当列具有NaN值时,调用df的第一行或最后一行索引不能用作解决方法。 - fact_finder
你期望的输出是什么样子的?列表?数据框架?序列? - Scott Boston
预期的输出最容易被视为一个数据框,列出每个变量及其最大和最小深度。并且可以方便地通过格式 depth_df['x1']['min']depth_df['x3']['max'] 来调用值。谢谢。 - fact_finder
这与您最初要求的完全不同:“理想的解决方案将为x1的第一次出现产生深度指数(503),为x2的第一次出现产生深度指数(502),并为x3的最后一次出现产生深度指数(504)”,根据此内容:您没有提及任何有关预期数据帧的最小和最大有效索引的信息。 - anky
1
对于没有指定额外任务的 anky_91,我感到抱歉。我面临的主要挑战是获取索引。将输出作为数据框是一个方便的奖励。我很感激能看到你和其他人对这个任务的方法。 - fact_finder
4个回答

5

first_valid_index() 和 last_valid_index() 可以用于处理IT技术相关内容。

    >>> df
             x1    x2    x3
    Depth
    500     NaN   NaN  25.0
    501     NaN   NaN  27.0
    502     NaN  33.0  24.0
    503     4.0  32.0  18.0
    504    12.0  45.0   5.0
    505     8.0  38.0   NaN
    >>> df["x1"].first_valid_index()
    503
    >>> df["x2"].first_valid_index()
    502
    >>> df["x3"].first_valid_index()
    500
    >>> df["x3"].last_valid_index()
    504

4
您可以使用agg函数进行操作:
df.notna().agg({'x1':'idxmax','x2':'idxmax','x3':lambda x: x[::-1].idxmax()})
#df.notna().agg({'x1':'idxmax','x2':'idxmax','x3':lambda x: x[x].last_valid_index()})

x1    503
x2    502
x3    504

另一种方法是检查第一行是否为NaN,根据此应用条件:
np.where(df.iloc[0].isna(),df.notna().idxmax(),df.notna()[::-1].idxmax())

[503, 502, 504]

1
我认为OP想要自动检测哪一列应用了[::-1].idxmax(),哪一列只是使用了idxmax() - Quang Hoang
@QuangHoang基于此添加了另一个解决方案。 - anky

2

IIUC

df.stack().groupby(level=1).head(1)
Out[619]: 
Depth    
500    x3    25.0
502    x2    33.0
503    x1     4.0
dtype: float64

2

如果我理解正确的话,让我们尝试这个:

最初的回答:

pd.concat([df.apply(pd.Series.first_valid_index),
           df.apply(pd.Series.last_valid_index)], 
           axis=1, 
           keys=['Min_Depth', 'Max_Depth'])

输出:

      Min_Depth   Max_Depth
x1          503         505
x2          502         505
x3          500         504

最初的回答
或者转置输出:
pd.concat([df.apply(pd.Series.first_valid_index),
           df.apply(pd.Series.last_valid_index)], 
           axis=1, 
           keys=['Min_Depth', 'Max_Depth']).T

输出:

            x1   x2   x3
Min_Depth  503  502  500
Max_Depth  505  505  504

使用apply函数和函数列表:

将apply函数应用于函数列表:

df.apply([pd.Series.first_valid_index, pd.Series.last_valid_index])

输出:

                    x1   x2   x3
first_valid_index  503  502  500
last_valid_index   505  505  504

稍作更名:

df.apply([pd.Series.first_valid_index, pd.Series.last_valid_index])\
  .set_axis(['Min_Depth', 'Max_Depth'], axis=0, inplace=False)

输出:

            x1   x2   x3
Min_Depth  503  502  500
Max_Depth  505  505  504

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