【问题标题】:create a new column in pandas DataFrame based on two others which contain NaN values根据包含 NaN 值的其他两个列在 pandas DataFrame 中创建一个新列
【发布时间】:2020-09-10 04:26:34
【问题描述】:

我有一只熊猫DataFramedf

                  L C
0         [1, 2, 3] 5
1       [4, nan, 6] 0
2   [nan, nan, nan] 15

还有一个DataFrameother

    C
0   0
1   25
2   0

然后我将 other 附加到 df 并在 L 列中添加 3 行具有 NaN 值。

                  L C   
0         [1, 2, 3] 5   
1       [4, nan, 6] 0   
2   [nan, nan, nan] 15  
0               NaN 0   
1               NaN 25  
2               NaN 0   

我想创建一个列,如果 L 列是 NaN 并且 C0 那么它将获得价值 1 否则它将获得价值 0。我还使用不包含 NaN 值的行进行计算,但这超出了本文的目的。

我发现 Pandas 处理Nan 值的方式是pd.isna()

我创建了函数

def check_cols(L, C):
  if pd.isna(L) and C == 0:
    return 1
  elif pd.isna(L) and C != 0:
    return 0 

我在每一行都应用这个函数

df['col'] = df.apply(lambda row: check_cols(row.L,row.C), axis=1)

但我得到了错误

具有多个元素的数组的真值是不明确的。使用 a.any() 或 a.all()

因为它检查列表中的每个元素是否为NaN。我不想检查列表的元素是否有NaN,我想检查是否有一个列表(即使所有元素都是nan)或NaN 值。另一种方法是使用pd.isna() 像这样创建一个列

                  L C   is_NaN
0         [1, 2, 3] 5   False
1       [4, nan, 6] 0   False
2   [nan, nan, nan] 15  False
0            NaN    0   True
1            NaN    25  True
2            NaN    0   True

然后将三列作为函数的参数,这将起作用。我想做同样的检查,如果有一个列表,如果有一个 NaN 值,在函数内,而不必创建额外的列。

如果有人能解释为什么在第一种情况下它会检查列表的每个元素,而在第二种情况下它会进行我想要的检查,和/或提供一些来源,那就太好了。

【问题讨论】:

    标签: python pandas dataframe multiple-columns nan


    【解决方案1】:

    异常背后的原因是您应该使用& 而不是and,而且if condition 不能评估为TrueFalse,因为输出是布尔值的Series。示例:

    pd.isna(df.L) & df.C == 0
    
    0     True
    1     True
    2     True
    0     True
    1    False
    2     True
    dtype: bool
    

    if condition 无法评估上述结果。

    这是一个直接返回您提到的条件的解决方案:

    import pandas as pd
    import numpy as np
    
    def check_cols(L, C):
        return pd.isna(df.L) & (df.C == 0)
    
    data = {
        'L': [[1, 2, 3], [4, np.nan, 6], [np.nan, np.nan, np.nan], np.nan, np.nan, np.nan],
        'C': [5, 0, 15, 0, 25, 0]}
    
    df = pd.DataFrame(data=data, index=[0, 1, 2, 0, 1 ,2])
    
    res = check_cols(df.L, df.C)
    df['res'] = res
    df
    

    # EDIT:根据 cmets 更新解决方案

    那么问题是您将pd.isna 应用于列表 - 例如在第一行中的第一行L = [1, 2, 3] 并且无法由if condition 评估。

    import pandas as pd
    import numpy as np
    
    def check_cols(L, C):
        if not isinstance(L, list) and np.isnan(L) and C == 0:
            return 1
        elif not isinstance(L, list) and np.isnan(L) and C != 0:
            return 0 
        else:
            # when L is a list
            return 1
    
    data = {
        'L': [[1, 2, 3], [4, np.nan, 6], [np.nan, np.nan, np.nan], np.nan, np.nan, np.nan],
        'C': [5, 0, 15, 0, 25, 0]
    }
    
    df = pd.DataFrame(data=data, index=[0, 1, 2, 0, 1 ,2])
    
    df['col'] = df.apply(lambda row: check_cols(row.L,row.C), axis=1)
    df
    

    编辑 2:我决定选择 np.nan,但它也适用于 pd.na

    【讨论】:

    • 感谢您的回答。你是对的,我没有写完全正确。 check_cols 函数与 apply() 一起使用。我将编辑我的帖子。我使用 apply 的原因是因为正如我提到的,如果值不是 NaN 我也会进行其他计算,我对值是否是 NaN 不感兴趣。
    • 我更新了添加要求的答案。在 if 条件下问题仍然相同,我们需要一个可以评估为 True 或 False 的值,并且当它使用列表运行时,它将返回 [False, False, True] 例如。
    • 基本上我想要在函数内执行与df.L.isna() 在方法内执行的相同检查,换句话说,isNaN 列。此检查不会打扰列表有多少元素以及哪些值,它只是检查是否存在列表或 NaN 值,如果我理解正确的话。这可能吗?
    猜你喜欢
    • 1970-01-01
    • 2021-03-19
    • 2020-08-18
    • 1970-01-01
    • 2020-06-02
    • 2021-07-08
    • 2020-11-14
    • 1970-01-01
    • 2020-04-25
    相关资源
    最近更新 更多