首页 > 解决方案 > Pandas 错误:有条件地更改单元格字符串值时出现链式索引错误

问题描述

大家好,我在使用链式索引/返回副本而不是Pandas 中的视图时遇到错误。这是我的代码:

import pandas as pd 
duplicates = pd.read_csv("dupes_test.csv", parse_dates=["Updated At"])
dupe_df = pd.DataFrame(duplicates)
dupe_sorted = dupe_df.sort_values(['Email Address', 'Updated At'], ascending=False)

数据框

cols_to_change = list(dupe_sorted.columns)
opt_out_count = 0 
unchanged_count = 0
error = 0 

这是我的for循环:

for dupe in range (0, dupe_sorted.shape[0]):
    try:
        if dupe_sorted["Email Address"].iloc[dupe] == dupe_sorted["Email Address"].iloc[dupe + 1]:
            for col in cols_to_change:
                if dupe_sorted[col].iloc[dupe + 1] == 'Opt Out':
                    dupe_sorted[col].iloc[dupe] = "Opt Out"
                    opt_out_count +=1
        else:
            unchanged_count +=1
    except:
        error += 1 

print("We're Done")

错误信息:

//anaconda3/envs/DtownPlayground/lib/python3.6/site-packages/pandas/core/indexing.py:670: SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrame

See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
  self._setitem_with_indexer(indexer, value)

我的输出似乎有所不同,有时它可以正常工作,我得到以下输出:

print(f"Opted Out: {opt_out_count}, Unchanged: {unchanged_count}, Error: {error}")
Opted Out: 22, Unchanged: 8, Error: 1

清理数据框

其他时候它不会更新任何值。我想我很困惑,因为我没有使用链式索引,而且我不知道为什么 Pandas 会给我这个警告信息。另外,让我知道是否应该以其他格式粘贴数据框以方便使用!

标签: pythonexcelpandascsv

解决方案


本质上,您试图在数据框的切片上分配单个单元格值,因此会发出警告:

dupe_sorted[col].iloc[dupe] = "Opt Out"

通常在 Pandas 操作中,您希望在一次调用中分配整个系列(即列),称为矢量化操作,而不是按行和列单元格。同样,在 Numpy 操作中,您希望在一次调用中分配 Ndarray,而不是按单元分配。

因此,考虑合并DataFrame.shift相同数据的版本以捕获下一行值。然后用条件逻辑重新分配,numpy.where, 每列。==并使用操作符的函数形式,Series.eq但两种方法都有效:

cols_to_change = dupe_sorted.columns.tolist()

# MERGE ON SHIFT FORWARD
dupe_sorted = dupe_sorted.join(dupe_sorted.shift(-1), how='left', rsuffix = '_')

# ITERATE ACROSS COLUMNS FOR SERIES ASSIGNMENT
for col in cols_to_change:
    dupe_sorted[col] = np.where((dupe_sorted['Email Address'].eq(dupe_sorted['Email Address_'])) &
                                (dupe_sorted[col+'_'].eq('Opt Out')),
                                'Opt Out',
                                dupe_sorted[col])

# REMOVE SHIFTED COLUMNS    
final_df = dupe_sorted.reindex(cols_to_change, axis='columns')

推荐阅读