如何处理熊猫数据帧中特定长度序列中的缺失值?

背心

精华:

如果一列包含一个比5个缺失值更多的序列,我想从该数据框中删除相应的索引。所以在下面的数据框中...

                A       B
2017-01-01 -0.0053 -0.0062
2017-01-02     NaN  0.0016
2017-01-03     NaN  0.0043
2017-01-04     NaN -0.0077
2017-01-05     NaN -0.0070
2017-01-06     NaN  0.0058
2017-01-07  0.0024 -0.0074
2017-01-08  0.0018  0.0086
2017-01-09  0.0020  0.0012
2017-01-10 -0.0031 -0.0020
2017-01-11  0.0027     NaN
2017-01-12 -0.0050     NaN
2017-01-13 -0.0063     NaN
2017-01-14  0.0066  0.0095
2017-01-15  0.0039  0.0028

...我想删除索引2017-01-022017-01-06以便所需的输出如下所示:

                 A       B
2017-01-01 -0.0053 -0.0062
2017-01-07  0.0024 -0.0074
2017-01-08  0.0018  0.0086
2017-01-09  0.0020  0.0012
2017-01-10 -0.0031 -0.0020
2017-01-11  0.0027     NaN
2017-01-12 -0.0050     NaN
2017-01-13 -0.0063     NaN
2017-01-14  0.0066  0.0095
2017-01-15  0.0039  0.0028

我如何有效地做到这一点?


细节:

这是一个重现数据帧的代码段:

# imports
import pandas as pd
import numpy as np
np.random.seed(1234)

# Reproducible data sample
def df_sample(rows, names):
    ''' Function to create data sample with random returns

    Parameters
    ==========
    rows : number of rows in the dataframe
    names: list of names to represent assets

    Example
    =======

    >>> returns(rows = 2, names = ['A', 'B'])

                  A       B
    2017-01-01  0.0027  0.0075
    2017-01-02 -0.0050 -0.0024
    '''
    listVars= names
    rng = pd.date_range('1/1/2017', periods=rows, freq='D')
    df_temp = pd.DataFrame(np.random.randint(-100,100,size=(rows, len(listVars))), columns=listVars) 
    df_temp = df_temp.set_index(rng)
    df_temp = df_temp / 10000

    return df_temp

df = df_sample(15,list('AB'))

我知道的并发症

如果数据框在多个列之间具有缺失值的重叠索引,如下所示:

                 A       B
2017-01-01 -0.0053 -0.0062
2017-01-02     NaN  0.0016
2017-01-03     NaN  0.0043
2017-01-04     NaN     NaN
2017-01-05     NaN     NaN
2017-01-06     NaN     NaN
2017-01-07  0.0024     NaN
2017-01-08  0.0018     NaN
2017-01-09  0.0020  0.0012
2017-01-10  NaN    -0.0020

...那么我想任何使用apply逐列的解决方案都将呈现这样的临时数据帧...

                 A       B
2017-01-01 -0.0053 -0.0062
2017-01-07  0.0024     NaN
2017-01-08  0.0018     NaN
2017-01-09  0.0020  0.0012
2017-01-10  NaN    -0.0020

...,然后可能会忽略column Bfrom2017-01-04的原始缺失索引2017-01-08也许那只是人们必须接受的东西。但理想情况下,该解决方案应认识到那些索引最初代表5个顺序丢失的值,并且也删除了这些索引,因此结果数据帧如下所示:

                 A       B
2017-01-01 -0.0053 -0.0062
2017-01-09  0.0020  0.0012
2017-01-10  NaN    -0.0020

(但是那最后的NaN呢?我会简单地说fill forward。但是对每个缺失的值执行相同操作将使事情走得更远。)

因此,我认为这可能比我最初怀疑的要复杂得多(也许这就是该函数pandas.DataFrame.dropna没有特定参数的原因)。


我试过的

1. pandas.DataFrame.dropna

我认为该参数thresh是使用pandas.DataFrame.dropna的一种方式,但是根据文档,该参数为现有值(而不是缺少值)设置了阈值:

thresh:int,默认值无

int值:要求许多非NA值

2.逐列定义和查找nan的模式

以下是基于此处建议答案的可能解决方案但是,它确实需要您定义要在一个序列中查找5个且仅5个缺失的价位。为了完成该解决方案,我还必须在代表所有列的缺失序列的索引的所有列表中找到索引的并集,然后对符合该条件的数据帧进行子集化。

感谢您提出任何其他建议!

这是简单复制粘贴的全部内容:

import pandas as pd
import numpy as np


np.random.seed(1234)

# Reproducible data sample
def df_sample(rows, names):
    ''' Function to create data sample with random returns

    Parameters
    ==========
    rows : number of rows in the dataframe
    names: list of names to represent assets

    Example
    =======

    >>> returns(rows = 2, names = ['A', 'B'])

                  A       B
    2017-01-01  0.0027  0.0075
    2017-01-02 -0.0050 -0.0024
    '''
    listVars= names
    rng = pd.date_range('1/1/2017', periods=rows, freq='D')
    df_temp = pd.DataFrame(np.random.randint(-100,100,size=(rows, len(listVars))), columns=listVars) 
    df_temp = df_temp.set_index(rng)
    df_temp = df_temp / 10000

    return df_temp

df = df_sample(15,list('AB'))

df['A'][1:6] = np.nan
df['B'][3:8] = np.nan
dfi = df

# convert to boolean values
df = dfi
df = df.isnull()

# specify pattern
pattern = [True,True, True, True, True]

# prepare for a for loop
idx = []

# loop through all columns and identify sequence of missing values
for col in df:
    df_temp = df[col].to_frame()

    matched = df_temp.rolling(len(pattern)).apply(lambda x: all(np.equal(x, pattern)))
    matched = matched.sum(axis = 1).astype(bool)
    idx_matched = np.where(matched)[0]
    subset = [range(match-len(pattern)+1, match+1) for match in idx_matched]

    result = pd.concat([df.iloc[subs,:] for subs in subset], axis = 0).index
    idx.append(result)
print(idx)

输出(nan序列的索引逐列):

    [DatetimeIndex(['2017-01-02', '2017-01-03', '2017-01-04', '2017-01-05','2017-01-06'],
          dtype='datetime64[ns]', freq=None),
    DatetimeIndex(['2017-01-04', '2017-01-05', '2017-01-06', '2017-01-07', '2017-01-08'],
          dtype='datetime64[ns]', freq=None)]
洛兹

这应该为您解决。它直到最后都不会删除行,因此它将根据您在第二种情况下正确解析多列。我已将“df复杂性”部分中的用于以下代码的输出。

说明:

  • 我们创建了另一个df,其中的NaN值被分配为零,而每个有限值都被分配为1(如果您的初始df值具有零值,则需要先将其映射到此哑元中的任何其他数字df2,然后是.fillna(0).astype('bool')

  • 按每列的累加总和分组,使我们能够找到连续的NaN超过5个的位置然后与原始df进行比较,以确保我们没有捕获第一个非null值。

  • 掩码是应该删除的任何行的末尾创建,因此您可以正确地为具有重叠NaN值的多列解决掩码

这是代码:

import pandas as pd
import numpy as np

## If the initial df contains values of 0 do this instead of the first line below
#df2 = df.copy()
#df2[df2==0] = 0.01
#df2 = df2.fillna(0).astype('bool').cumsum()

# Min number of consecutive NaN values to begin dropping
n_cons = 5

df2 = df.fillna(0).astype('bool').cumsum()
for col in df2.columns:
    df2[col] = df2.groupby(col)[col].transform(lambda x: np.size(x) > n_cons)
    df2[col] = df2[col] & df[col].isnull()

mask = df2.any(axis=1)

df[~mask]
#                 A       B
#2017-01-01 -0.0053 -0.0062
#2017-01-09  0.0020  0.0012
#2017-01-10     NaN -0.0020

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章