代码之家  ›  专栏  ›  技术社区  ›  gorjan

pandas:根据条件在数据帧组末尾剥离行

  •  1
  • gorjan  · 技术社区  · 6 年前

    假设我有以下数据帧:

    df = pd.DataFrame({"id": [1, 1, 1, 2, 2, 2, 3, 3, 3, 3], "date": [pd.Timestamp(2002, 2, 2), pd.Timestamp(2003, 3, 3), pd.Timestamp(2004, 4, 4), pd.Timestamp(2005, 5, 5), pd.Timestamp(2006, 6, 6), pd.Timestamp(2007, 7, 7), pd.Timestamp(2008, 8, 8), pd.Timestamp(2009, 9, 9), pd.Timestamp(2010, 10, 10), pd.Timestamp(2011, 11, 11)], "numeric": [0.9, 0.4, 0.2, 0.6, np.nan, 0.8, 0.7, np.nan, np.nan, 0.5], "nominal": [0, 1, 0, 1, 0, 0, 0, 1, 1, 1]})
    

    我想要实现的是在每个组的末尾剥离行(假设行是按 id ,以便删除行,直到 non-nan 值将出现在 numeric 列。此外,每个组的最后一行将始终具有 非南 价值 数字的 列和最后一行应始终被删除。因此,得到的数据帧是:

    result_df = pd.DataFrame({"id": [1, 1, 2, 3], "date": [pd.Timestamp(2002, 2, 2), pd.Timestamp(2003, 3, 3), pd.Timestamp(2005, 5, 5), pd.Timestamp(2008, 8, 8)], "numeric": [0.9, 0.4, 0.6, 0.7], "nominal": [0, 1, 1, 0]})
    

    有关如何到达结果数据帧的更多说明:

    • 为了 id == 1 仅删除最后一行,因为在最后一行之前的行中存在 数字的 列。
    • 为了 id == 2 最后两行将被删除,因为默认情况下,最后一行之前的行将被删除 nan 价值。
    • 为了 id == 3 最后三行被删除,因为默认情况下最后一行和第一行被删除 非南 值在第四行,从下面开始计算。

    此外,我目前正在做的是:

    df.groupby("id", as_index=False).apply(lambda x: x.iloc[:-1]).reset_index(drop=True)
    

    但是,这只会删除每个组的最后一行,我想删除最后一行 N 基于上述条件的行。

    请让我知道,如果你需要任何进一步的信息,并期待您的答案!

    1 回复  |  直到 6 年前
        1
  •  2
  •   KRKirov    6 年前

    对于您发布的特定示例,在分组之前删除nans就可以了:

    df = df.dropna().groupby('id').apply(lambda x: x.iloc[:-1]).reset_index(drop=True)
    
    df
    Out[58]: 
       id       date  numeric  nominal
    0   1 2002-02-02      0.9        0
    1   1 2003-03-03      0.4        1
    2   2 2005-05-05      0.6        1
    3   3 2008-08-08      0.7        0
    

    如果您有一个不连续的nan,并且只想删除最后一个nan块:

    def strip_rows(X):    
        X = X.iloc[:-1, :]
        while pd.isna(X.iloc[-1, 2]):        
            X = X.iloc[:-1, :]
        return X
    
    df_1 = pd.DataFrame({"id": [1, 1, 1, 2, 2, 2, 3, 3, 3, 3, 3, 3],
                       "date": [pd.Timestamp(2002, 2, 2),
                                pd.Timestamp(2003, 3, 3), 
                                pd.Timestamp(2004, 4, 4), 
                                pd.Timestamp(2005, 5, 5), 
                                pd.Timestamp(2006, 6, 6),
                                pd.Timestamp(2007, 7, 7),
                                pd.Timestamp(2008, 8, 8),
                                pd.Timestamp(2009, 9, 9),
                                pd.Timestamp(2010, 10, 10), 
                                pd.Timestamp(2011, 11, 11),
                                pd.Timestamp(2011, 12, 12),
                                pd.Timestamp(2012, 1, 1)],
                        "numeric": [0.9, 0.4, 0.2, 0.6, np.nan, 0.8, 0.7, np.nan, np.nan, 0.5, np.nan, 0.3],
                        "nominal": [0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1]})
    
    df_2 = df_1.groupby('id').apply(strip_rows).reset_index(drop=True)
    
    df_1
    Out[151]: 
        id       date  numeric  nominal
    0    1 2002-02-02      0.9        0
    1    1 2003-03-03      0.4        1
    2    1 2004-04-04      0.2        0
    3    2 2005-05-05      0.6        1
    4    2 2006-06-06      NaN        0
    5    2 2007-07-07      0.8        0
    6    3 2008-08-08      0.7        0
    7    3 2009-09-09      NaN        1
    8    3 2010-10-10      NaN        1
    9    3 2011-11-11      0.5        1
    10   3 2011-12-12      NaN        0
    11   3 2012-01-01      0.3        1
    
    df_2
    Out[152]: 
       id       date  numeric  nominal
    0   1 2002-02-02      0.9        0
    1   1 2003-03-03      0.4        1
    2   2 2005-05-05      0.6        1
    3   3 2008-08-08      0.7        0
    4   3 2009-09-09      NaN        1
    5   3 2010-10-10      NaN        1
    6   3 2011-11-11      0.5        1