bounty将在23小时后过期。回答此问题可获得+200声望奖励。Sean正在寻找来自知名来源的答案。
我当前有一个形状为(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
相同的功能?
2条答案
按热度按时间g6ll5ycj1#
您有许多地方需要我们改进。
首先,尽量不要在 Dataframe 上循环,而是使用panda包提供的一些工具。但是,如果无法避免,在 Dataframe 的行上循环最好使用
.iterrows()
方法,而不是.to_dict()
。记住,如果使用iterrows
,在迭代时不应该修改 Dataframe 。然后,对于iloc/loc使用。Loc使用的是键名(像字典一样),而iloc使用的是键索引(像数组一样)。这里
idx
是索引,而不是键名,那么如果键名与索引不相同,df.loc[idx, 'labels']
将导致一些错误。我们可以很容易地使用它们,如下所示:df.iloc[idx, : ].loc['labels']
.要说明
loc
和iloc
之间的区别:请记住,链接 Dataframe 将返回数据的副本,而不是切片:这就是为什么
df.iloc[idx]['labels']
和df.iloc[idx, : ].loc['labels']
都会触发警告。如果labels
是第i列,则df.iloc[idx, i ]
不会触发警告。xkrw2x1b2#
请注意,在您的情况下,
SettingWithCopyWarning
是一个有效的警告,因为链接的赋值未按预期工作。df.iloc[idx]
返回切片的副本,而不是原始对象中的切片。因此,df.iloc[idx]['labels'] = '|'.join(labels)
修改行的副本,而不是原始df
的行。当 Dataframe 具有混合数据类型时,似乎会发生这种情况。关于
.loc
和.iloc
的不同结果,这是因为行标签与行整数位置不同(可能是由于训练测试拆分)。当行标签不存在时,.loc
无法在现有行中找到它,因此它生成新行(.loc
获取带有行(和/或列)标签的行(和/或列),而.iloc
获取带有整数位置的行(和/或列)。)请在解答后找到示例。
溶液
基本思想:您应该避免链式赋值并且使用正确的标签/整数位置。
溶液1:
reset_index
和.loc
如果不需要保留行索引,一个解决方案是在代码之前执行
reset_index
,并使用df.loc[idx, 'labels'] = '|'.join(labels)
。第一个
这将使 Dataframe 行标签与行整数位置相同。因此
.loc[n, 'labels']
与.iloc[n, 'labels']
引用相同的内容。解决方案2:使用列整数位置“labels”和
.iloc
范例:将第4列的
labels
更新为100
更多示例
有效
SettingWithCopyWarning
的示例假设我想将第一行的
labels
更新为100
。它返回了警告,并且无法更新该值。
如果所有列都具有相同的数据类型(例如:所有
str
,所有int
),iloc
将工作,并且不会返回SettingWithCopyWarning
。显然,pandas
在进行链式赋值时处理混合类型和单类型 Dataframe 的方式不同。引用指向此Github issue的post。您也可以阅读post或pandas文档,以更好地理解链接赋值。
.loc
的附加行示例在我们的示例中,行标签为
(0, 2, 4, 5)
,而行整数位置为(0, 1, 2, 3)
。当您将.loc
与不存在的标签一起使用时,它将创建一个新行。