【问题标题】:Filter first element in a list that matches a criteria for each row pandas过滤列表中与每行 pandas 的条件匹配的第一个元素
【发布时间】:2020-02-07 04:57:11
【问题描述】:

问题/问题:我想创建另一列,其中包含与条件匹配的列表中的第一列(许多列)/或值(与“nan”不同)。

我正在处理一个数据框,该数据框具有多个用作标志的列,每一列都是不同类型的标志。这是它的样子:

         id_number  createdat  ... flag_3.3.3.2.1 flag_3.3.3.2.2 flag_3.3.3.3.1
1             718v 2019-08-14  ...            nan      3.3.3.2.2      3.3.3.3.1
2             566m 2019-07-10  ...            nan            nan            nan
3             636p 2019-06-12  ...      3.3.3.2.1            nan      3.3.3.3.1
4             630r 2019-06-30  ...            nan            nan            nan
26815         066p 2019-08-24  ...      3.3.3.2.1      3.3.3.2.2      3.3.3.3.1
26816         769b 2019-08-10  ...            nan            nan            nan

我设法创建了一个列,该列生成包含“flag_”的列的所有值的列表:

payday_cols = [col for col in df if col.startswith('flag_')]
df['flagging'] = df[payday_cols].values.tolist()
print(df)
         id_number  ... flag_3.3.3.3.1                                           flagging
1             718v  ...            nan  [nan, nan, nan, nan, nan, nan, nan, nan, nan, ...
2             566m  ...            nan  [nan, nan, nan, nan, nan, nan, nan, nan, nan, ...
3             636p  ...            nan  [nan, nan, 2.2, nan, nan, nan, nan, nan, nan, ...
4             630r  ...            nan  [nan, nan, nan, 3.1, nan, nan, nan, nan, 3.3.2...                                          ...
26815         066p  ...      3.3.3.3.1  [nan, nan, nan, nan, 3.2, nan, nan, nan, nan, ...
26816         769b  ...            nan  [1, nan, nan, nan, nan, nan, nan, nan, 3.3.2.1...

我缺少的是一种创建最终列的方法,该列包含与nan 不同的列表的第一个值,或者如果没有与nan 不同的值,则为 nan。输出是这样的:

         id_number  ... flag_3.3.3.3.1                                           flagging      flag
1             718v  ...            nan  [nan, nan, nan, nan, nan, nan, nan, nan, nan, ...       nan
2             566m  ...            nan  [nan, nan, nan, nan, nan, nan, nan, nan, nan, ...       nan
3             636p  ...            nan  [nan, nan, 2.2, nan, nan, nan, nan, nan, nan, ...       2.2
4             630r  ...            nan  [nan, nan, nan, 3.1, nan, nan, nan, nan, 3.3.2...       3.1
26815         066p  ...      3.3.3.3.1  [nan, nan, nan, nan, 3.2, nan, nan, nan, nan, ...       3.2
26816         769b  ...            nan  [1, nan, nan, nan, nan, nan, nan, nan, 3.3.2.1...   3.3.2.1

非常感谢,如果您需要我生成与这些类似的值,以便您可以重新创建此案例,我将使用它来编辑这篇文章。

【问题讨论】:

    标签: python pandas list filtering


    【解决方案1】:

    方法一

    试试bfill.iloc

    df[payday_cols].bfill(1).iloc[:,0]
    
    Out[92]:
    1        3.3.3.2.2
    2              NaN
    3        3.3.3.2.1
    4              NaN
    26815    3.3.3.2.1
    26816          NaN
    Name: flag_3.3.3.2.1, dtype: object
    

    方法二

    另一种解决方案是在 notna 上使用 numpy argmax 并将结果传递给 lookup

    m = df[payday_cols].notna().values.argmax(1)
    df[payday_cols].lookup(df.index, np.array(payday_cols)[m])
    
    Out[145]: array(['3.3.3.2.2', nan, '3.3.3.2.1', nan, '3.3.3.2.1', nan], dtype=object)
    

    注意:输出基于此样本

    In [83]: df
    
    Out[83]:
          id_number   createdat flag_3.3.3.2.1 flag_3.3.3.2.2 flag_3.3.3.3.1  
    1          718v  2019-08-14            NaN      3.3.3.2.2      3.3.3.3.1
    2          566m  2019-07-10            NaN            NaN            NaN
    3          636p  2019-06-12      3.3.3.2.1            NaN      3.3.3.3.1
    4          630r  2019-06-30            NaN            NaN            NaN
    26815      066p  2019-08-24      3.3.3.2.1      3.3.3.2.2      3.3.3.3.1
    26816      769b  2019-08-10            NaN            NaN            NaN
    

    【讨论】:

    • 谢谢,我必须代表我进行一个小修复,它功能齐全!
    【解决方案2】:

    这应该可行。

    df = pd.DataFrame({
        "flagging": [[np.nan, np.nan, np.nan, np.nan], [np.nan, 2.2, np.nan, 0.2], [np.nan, 1.1, np.nan, np.nan], [np.nan, np.nan, np.nan, 3.1]]
    })
    
    def get_element(xs):
        xs = [x for x in xs if not pd.isna(x)]
        if xs:
            return xs[0]
        return np.nan
    
    df["flagging"].apply(get_element)
    

    输出:

    0    NaN
    1    2.2
    2    1.1
    3    3.1
    

    【讨论】:

    • 确实,我可以在函数中使用列表推导,然后应用它来生成预期的输出。谢谢!
    【解决方案3】:

    我的解决办法是:

    • 将包含列表的列转换为 DataFrame(应用 pd.Series 到每个元素)。
    • 根据first_valid_index对每一行应用一个函数。

    所以我们假设 df 是:

    df = pd.DataFrame({ "flagging": [
        [np.nan, np.nan, np.nan, np.nan], [np.nan, 2.2, np.nan, 0.2],
        [np.nan, 1.1, np.nan, np.nan], [np.nan, np.nan, np.nan, 3.1]]})
    

    定义如下函数:

    def func(x):
        ind = x.first_valid_index()
        return None if ind is None else x[ind]
    

    然后应用它:

    df.flagging.apply(pd.Series).apply(func, axis=1)
    

    【讨论】:

      猜你喜欢
      • 2018-07-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-06-13
      • 1970-01-01
      • 2012-09-21
      • 2018-02-25
      相关资源
      最近更新 更多