For Loop in Python Error: The truth value of a Series is ambiguous

For Loop in Python Error: The truth value of a Series is ambiguous

为什么这个 for 循环不起作用...?

我想得到一个包含交货年份的新列,它由这些列组成,但是,有很多 Nans,所以逻辑是 for 循环遍历列并且 returns 第一个非-Na值。最好的情况是交货日期,如果不存在,那么构建年份,如果即使不存在,那么至少机器投入使用时的投入使用日期。

df = pd.DataFrame({'Platform ID' : [1,2,3,4], "Delivery Date" : [str(2009), float("nan"), float("nan"), float("nan")],
                                              "Build Year" : [float("nan"),str(2009),float("nan"), float("nan")], 
                                              "In Service Date" : [float("nan"),str("14-11-2010"), str("14-11-2009"), float("nan")]})
df.dtypes
df

def delivery_year(delivery_year, build_year, service_year):
    out = []
    for i in range(0,len(delivery_year)):
        if delivery_year.notna():
            out[i].append(delivery_year)
        if (delivery_year[i].isna() and build_year[i].notna()):
            out[i].append(build_year)
        elif build_year[i].isna():
            out[i].append(service_year.str.strip().str[-4:])
        else:
            out[i].append(float("nan"))
    return out

df["Delivery Year"] = delivery_year(df["Delivery Date"], df["Build Year"], df["In Service Date"])

当我 运行 这个函数时,我得到这个错误,我不知道为什么...

ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().

预期产量(交货年份列):

更新 3

我以与您相同的方式重写了您的函数,因此没有改变您的列的逻辑和类型。我让你比较两个版本:

def delivery_year(delivery_date, build_year, service_year):
    out = []
    for i in range(len(delivery_date)):
        if pd.notna(delivery_date[i]):
            out.append(delivery_date[i])
        elif pd.isna(delivery_date[i]) and pd.notna(build_year[i]):
            out.append(build_year[i])
        elif pd.isna(build_year[i]) and pd.notna(service_year[i]):
            out.append(service_year[i].strip()[-4:])
        else:
            out.append(float("nan"))
    return out

df["Delivery Year"] = delivery_year(df["Delivery Date"],
                                    df["Build Year"],
                                    df["In Service Date"])

备注:

  1. 我更改了你的第一个参数的名称,因为 delivery_year 也是你的函数的名称,所以它可能会造成混淆。

  2. 我还用它们的等效函数替换了 .isna().notna() 方法:pd.isna(...)pd.notna(...)

  3. 第二个if变成了elif

更新 2

使用combine_first替换你的函数。 combine_first 使用值为 NaN 的第二个系列更新第一个系列 ('Delivery Date')。您可以将它们链接起来以填充您的 'Delivery Year'.

df['Delivery Year'] = df['Delivery Date'] \
                          .combine_first(df['Build Year']) \
                          .combine_first(df['In Service Date'].str[-4:])

输出:

>>> df
   Platform ID Delivery Date Build Year In Service Date Delivery Year
0            1          2009        NaN             NaN          2009
1            2           NaN       2009      14-11-2010          2009
2            3           NaN        NaN      14-11-2009          2009
3            4           NaN        NaN             NaN           NaN

更新

您忘记了 [i]:

if delivery_year[i].notna():

Series 的真值不明确:

>>> delivery_year.notna()
0     True  # <- 2009
1    False  # <- NaN
2    False
3    False
Name: Delivery Date, dtype: bool

Pandas 应该考虑该系列是 True (2009) 还是 False (NaN)?

您必须将结果与 .any().all()

相加
>>> delivery_year.notna().any()
True  # because there is at least one non nan-value.

>>> delivery_year.notna().all()
False  # because all values are not nan.

据我所知,你的错误有解决方案。 如果您想在第一次出现 Non-nan 值时触发 IF 语句, 像这样使用 .any()。

if delivery_year.notna().any():
            out[i].append(delivery_year)

您必须指定是否要从特定列或 'All' 值中过滤掉 'Any' 值。 :)

报错的原因之一是虽然你的Delivery Date、Build Year和In Service Date是object类型,但是其中的NaN值是float类型(见下图)

解决这个问题的方法之一是将三列转换为 str 类型:

df["Delivery Date"] = df["Delivery Date"].astype(str)
df["Build Year"] = df["Build Year"].astype(str)
df["In Service Date"] = df["In Service Date"].astype(str)

然后我修改了你的函数如下:

def delivery_year(delivery_year, build_year, service_year):
    out = []
    for i in range(0,len(delivery_year)):
        if len(delivery_year[i])>=4:
            out.append(delivery_year[i])
        elif (len(delivery_year[i])<4) & (len(build_year[i])>=4):
            out.append(build_year[i])
        elif (len(build_year[i])<4 and len(service_year[i])>=4):
            out.append(service_year[i].split("-")[-1])
        else:
            out.append(float("nan"))
    return out

df["Delivery Year"] = delivery_year(df["Delivery Date"], df["Build Year"], df["In Service Date"])

我正在检查大于 4 的长度,因为“NaN”作为字符串的长度将在上面的函数中检查为 3。这将 return 您需要的附加列,如附上屏幕截图