Pandas - 查找最长的连续非Nan值序列

9

我有一个名为 "df" 的pandas数据框,下面是一个示例:

   time  x
0  1     1
1  2     Nan 
2  3     3
3  4     Nan
4  5     8
5  6     7
6  7     5
7  8     Nan

真正的框架要大得多。我正在尝试查找“x”系列中最长的非NaN值区间,并打印出此框架的起始和结束索引。这可以实现吗?
谢谢
5个回答

9
这里提供了一个使用NumPy工具的向量化方法 -
a = df.x.values  # Extract out relevant column from dataframe as array
m = np.concatenate(( [True], np.isnan(a), [True] ))  # Mask
ss = np.flatnonzero(m[1:] != m[:-1]).reshape(-1,2)   # Start-stop limits
start,stop = ss[(ss[:,1] - ss[:,0]).argmax()]  # Get max interval, interval limits

样例运行 -

In [474]: a
Out[474]: 
array([  1.,  nan,   3.,  nan,  nan,  nan,  nan,   8.,   7.,   5.,   2.,
         5.,  nan,  nan])

In [475]: start, stop
Out[475]: (7, 12)

间隔被设置为每个起始和停止之间的差距给出了每个间隔的长度。因此,如果您通过“结束索引”想要获取非零元素的最后一个索引,我们需要从“停止”中减去一。请保留HTML标记。

1
非常棒的解决方案! - MaxU - stand with Ukraine
@JeffSaltfist 我对这个性能有很高的期望。因此,希望在你的大型数据集上,这会有意义! - Divakar
1
是的,这比我的少几个切片。很棒的答案,Divakar! - piRSquared
1
哇,刚刚运行了它...真的很强大。再次感谢,这段代码将被列入我的伟大代码片段清单中。 - Jeff Saltfist
1
对于想要查找NaN值分组的任何人,您可以在构建数组m时通过连接False值而不是True值来实现。 - vasekhlav
显示剩余6条评论

6

pandas

f = dict(
    Start=pd.Series.first_valid_index,
    Stop=pd.Series.last_valid_index,
    Stretch='count'
)

agged = df.x.groupby(df.x.isnull().cumsum()).agg(f)
agged.loc[agged.Stretch.idxmax(), ['Start', 'Stop']].values

array([ 4.,  6.])

numpy

def pir(x):
    # pad with np.nan
    x = np.append(np.nan, np.append(x, np.nan))
    # find where null
    w = np.where(np.isnan(x))[0]
    # diff to find length of stretch
    # argmax to find where largest stretch
    a = np.diff(w).argmax()
    # return original positions of boundary nulls
    return w[[a, a + 1]] + np.array([0, -2])

演示

pir(df.x.values)

array([4, 6])

a = np.array([1, np.nan, 3, np.nan, np.nan, np.nan, np.nan, 8, 7, 5, 2, 5, np.nan, np.nan])
pir(a)

array([ 7, 11])

4

你可以通过以下方式获取NaN的索引值:

import numpy as np

index = df['x'].index[df['x'].apply(np.isnan)]
df_index = df.index.values.tolist()
[df_index.index(indexValue) for indexValue in index]

>>> [0, 1, 3, 7]

那么一种解决方案是查看相邻索引值之间的最大差异,这将给出最长的非NaN值连续区间。


2
你的三行代码可以被更简单的代码替代,例如 df.index[pd.isnull(df['x'])].tolist() - Randy

3
也许更快的方法如下(鉴于你说你有一个很长的数据框,速度很重要):
In [19]: df = pd.DataFrame({'time':[1,2,3,4,5,6,7,8],'x':[1,np.NAN,3,np.NAN,8,7,5,np.NAN]})

In [20]: index = df['x'].isnull()

In [21]: df[index].index.values
Out[21]: array([1, 3, 7])

1
另一种方法是使用scipy.ndimage.measurements.label。它将对非空索引进行分割并将其分组和标记为不同的有效组。然后,您可以使用这些标签对数据框进行分组,并选择最大的组。 设置
import pandas as pd
import numpy as np
from scipy.ndimage.measurements import label
df = pd.DataFrame({'time':[1,2,3,4,5,6,7,8],'x':[1,np.NAN,3,np.NAN,8,7,5,np.NAN]})

获取最长的不含NaN的连续区间。
valid_rows = ~df.isnull().any(axis=1)
label, num_feature = label(valid_rows)
label_of_biggest_group =  valid_rows.groupby(label).count().drop(0).argmax()
print df.loc[label == label_of_biggest_group]

Result

   time    x
4     5  8.0
5     6  7.0
6     7  5.0

注意

标签0包含背景数据,即nan值,在你的nan数量大于或等于最大组的大小时必须删除。 num_feature是没有nan的同质区间的数量。


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