【问题标题】:Assigning new values to rows with iloc and loc produce different results. How do I avoid the SettingToCopyWarning same as iloc?使用 iloc 和 loc 为行分配新值会产生不同的结果。如何避免与 iloc 相同的 SettingToCopyWarning?
【发布时间】:2022-11-14 12:10:29
【问题描述】:

我目前有一个形状为 (16280, 13) 的 DataFrame。我想为单个列中的特定行分配值。我最初是这样做的:

for idx, row in enumerate(df.to_dict('records')):
    instances = row['instances']
    labels = row['labels'].split('|')

    for instance in instances:
        if instance not in relevant_labels:
            labels = ['O' if instance in l else l for l in labels]

        df.iloc[idx]['labels'] = '|'.join(labels)

但是由于最后一行,这一直返回SettingWithCopyWarning。我尝试将其更改为df.loc[idx, 'labels'] = '|'.join(labels),它不再返回警告,但在我的代码的后半部分导致错误。

我注意到使用iloc 时DataFrame 的大小为(16280, 13),使用loc 时为(16751, 13)。

如何防止打印警告并获得与使用iloc 相同的功能?

【问题讨论】:

    标签: python pandas


    【解决方案1】:

    您有很多我们可以在这里改进的地方。

    首先,尽量不要循环遍历数据框,而是使用 pandas 包提供的一些工具。 但是,如果无法避免,最好使用.iterrows() 方法而不是.to_dict() 来循环数据帧的行。请记住,如果使用iterrows,则不应在迭代时修改数据框。

    然后,用于 iloc/loc 用途。 Loc 使用键名(如字典),尽管 iloc 使用键索引(如数组)。这里idx是一个索引,不是key的名字,那么df.loc[idx, 'labels']如果key的名字和它的索引不一样会导致一些错误。我们可以像下面这样轻松地使用它们:df.iloc[idx, : ].loc['labels']

    为了说明 lociloc 之间的区别:

    df_example = pd.DataFrame({"a": [1, 2, 3, 4],
                               "b": ['a', 'b', 'a', 'b']},
                              index=[0, 1, 3, 5])
    
    print(df_example.loc[0] == df_example.iloc[0])  # 0 is the first key, loc and iloc same results
    print(df_example.loc[1] == df_example.iloc[1])  # 1 is the second key, loc and iloc same results
    try:
        print(df_example.loc[2] == df_example.iloc[2])  # 2 is not a key, then it will crash on loc (Keyerror)
    except KeyError:
        pass
    print(df_example.loc[3] == df_example.iloc[3])  # 3 the third key, then iloc and loc will lead different results
    try:
        print(df_example.loc[5] == df_example.iloc[5])  # 5 is the last key but there is no 6th key so it will crash on iloc (indexerror)
    except IndexError:
        pass
    

    请记住,链接数据框将返回数据的副本而不是切片:doc。这就是为什么 df.iloc[idx]['labels']df.iloc[idx, : ].loc['labels'] 都会触发警告。如果 labels 是您的第 i 列,则 df.iloc[idx, i ] 不会触发警告。

    【讨论】:

    • 感谢你的回答。但是,我仍然收到警告。 :( 还有,我用iterrows,后来改用to_dict('records'),因为听说后者比前者效率高很多,还推荐用iterrows吗?
    • 好的,我对链接 loc 和 iloc 是错误的,仍然对文档进行警告仔细检查。我将对此进行编辑。一般来说,尽量避免使用 iterrows() 或 to_dict(),性能差异很小,我更喜欢 iterrows(),因为你不必调用 enumerate。如果性能有问题,请尝试使用 apply 重构您的代码
    • 我猜由于您对标签的操作与前几行无关,因此您可以轻松地矢量化您的操作。您可以使用explode 将列表实例和标签转换为行,并使用isin 检查列实例中的所有数据是否都在相关标签中。
    猜你喜欢
    • 2015-10-14
    • 1970-01-01
    • 2021-08-29
    • 2016-10-21
    • 2018-02-08
    • 2019-01-28
    相关资源
    最近更新 更多