如何根据 python 中 select 列右侧的每行中的 nans 数量对数据帧进行子集化?

How to subset a dataframe by the number of nans in each row to the right of a select column in python?

我有一个数据框形式的订单簿,如下所示:

import pandas as pd
import numpy as np

months = list(range(1, 13))
li = list(map(str, months))
cols = ['ID']
cols.extend(li)

df = pd.DataFrame(np.random.randint(0,1000,size=(10, 13)), columns=cols)
df.loc[[1,2],'1':'12'] = np.nan
df.loc[3,'7':'12'] = np.nan
df.loc[5,'5':'12'] = np.nan
df.loc[7,'3':'8'] = np.nan
df.loc[9,'3':'10'] = np.nan

    ID      1      2      3      4      5      6      7      8      9     10     11     12
0  328   45.0  226.0  388.0  286.0  557.0  930.0  234.0  418.0  863.0  500.0  232.0  116.0
1  340    NaN    NaN    NaN    NaN    NaN    NaN    NaN    NaN    NaN    NaN    NaN    NaN
2  865    NaN    NaN    NaN    NaN    NaN    NaN    NaN    NaN    NaN    NaN    NaN    NaN
3  313  947.0  272.0  936.0  501.0  241.0  731.0    NaN    NaN    NaN    NaN    NaN    NaN
4  293  772.0  185.0    6.0  284.0  522.0  826.0  995.0  370.0   87.0  668.0  469.0   40.0
5  226   31.0  994.0  896.0  889.0    NaN    NaN    NaN    NaN    NaN    NaN    NaN    NaN
6  622  128.0  337.0   67.0  763.0  999.0  853.0  172.0  927.0  460.0  602.0  134.0  115.0
7  454  407.0    1.0    NaN    NaN    NaN    NaN    NaN    NaN   33.0   60.0  112.0  127.0
8  538  968.0  924.0  113.0  162.0  416.0   16.0   88.0  631.0  516.0  593.0   65.0  574.0
9  501  949.0  709.0    NaN    NaN    NaN    NaN    NaN    NaN    NaN    NaN  272.0  220.0

按照目前的情况,我依次遍历列和行,根据左侧单元格中的值填充每个单元格。

假设我在“5”月,这意味着我只对数据框的这一部分感兴趣:

    ID       5      6      7      8      9     10     11     12
0  328     557.0  930.0  234.0  418.0  863.0  500.0  232.0  116.0
1  340       NaN    NaN    NaN    NaN    NaN    NaN    NaN    NaN
2  865       NaN    NaN    NaN    NaN    NaN    NaN    NaN    NaN
3  313     241.0  731.0    NaN    NaN    NaN    NaN    NaN    NaN
4  293     522.0  826.0  995.0  370.0   87.0  668.0  469.0   40.0
5  226       NaN    NaN    NaN    NaN    NaN    NaN    NaN    NaN
6  622     999.0  853.0  172.0  927.0  460.0  602.0  134.0  115.0
7  454       NaN    NaN    NaN    NaN   33.0   60.0  112.0  127.0
8  538     416.0   16.0   88.0  631.0  516.0  593.0   65.0  574.0
9  501       NaN    NaN    NaN    NaN    NaN    NaN  272.0  220.0

并给定一个变量 term_len = 6,是否有一种有效的方法来识别哪个 ID's/indexes 有 6 个连续的单元格,其中来自列 '5' 的 NaN?

我期望的是要识别的行 [1, 2, 5, 9]。不是索引 4,因为它只有 4 个 NaN,也不是索引 3,因为该行不以 NaN 开头。

我能想到的唯一方法:

month = 5
subset = df.loc[:, str(month):]
term_len  = 6
idxs = pd.to_numeric(subset.apply(pd.Series.first_valid_index,axis=1))
idxsT = idxs - month - term_len
idxsT.index[(idxsT >= 0) | (idxsT.isna())]

Out: Int64Index([1, 2, 5, 9], dtype='int64')

是否有解决此问题的替代方法?

  1. 创建一个名为 m 的掩码,用于过滤具有 df.iloc[:,6:11] 的那些特定列。
  2. 然后,您可以将 .isnull() 添加到掩码,这将根据这些列中的所有单元格是否为空来 return True 或 False。
  3. 掩码的最后一部分是获取 .sum 并传递 axis=1,这将为您提供 True 的所有 sum 值26=]all columns for each row,因为True=1 and False=0,因为True/False是布尔数据type.So,m,给你一系列所选列的真值计数。
  4. 最后一步是简单地根据此掩码 df = df[m == 5] 过滤器过滤整个数据帧,以过滤具有 5 个真值的行,即指定列的所有行 NaN

代码:

m = df.iloc[:,6:11].isnull().sum(axis=1)
df = df[m == 5]

输出:

    ID  1       2       3   4   5   6   7   8   9   10  11      12
1   340 NaN     NaN     NaN NaN NaN NaN NaN NaN NaN NaN NaN     NaN
2   865 NaN     NaN     NaN NaN NaN NaN NaN NaN NaN NaN NaN     NaN
5   226 31.0    994.0   896.0   889.0   NaN NaN NaN NaN NaN     NaN NaN NaN
9   501 949.0   709.0   NaN NaN NaN NaN NaN NaN NaN NaN 272.0   220.0