在编程中,我们可能犯错,但这并不一定代表愚蠢,然而常常会导致意外结果。
有些错误就像明亮的钻石,很容易被察觉。即使你忽略它们,编译器(或解释器)也会通过报错提示我们。
另一方面,还存在一些“隐形”错误,难以察觉,但却可能引发严重问题。尽管这类错误不会触发警告,但可能导致函数或操作以出人意料的方式运行,从而产生未察觉到的结果变化。
我们接下来将深入探讨其中的三个问题。
假设促销数据存储在一个DataFrame中,看起来像下面这样(实际上不会这么小):
如果你想跟随并自己做示例,以下是用于创建这个DataFrame的Pandas代码:
import pandas as pd
promotion = pd.DataFrame(
{
"promotion_code": ["A2", "A1", "A2", "B1", "A2", None, "A2", "B1", None, "A1"],
"sales_qty": [34, 32, 26, 71, 44, 27, 64, 33, 45, 90],
"price": [24.5, 33.1, 64.9, 52.0, 29.0, 47.5, 44.2, 25.0, 42.5, 30.0]
}
)
计算每个促销代码的总销售数量非常简单。你只需要使用groupby
函数:
promotion.groupby("promotion_code").agg(
total_promo_sales = ("sales_qty", "sum")
)
# output
promotion_code total_promo_sales
A1 122
A2 168
B1 104
当你将它们相加以获得总销售数量时,你会得到394,但正确的总销售数量是466。
promotion_sales = promotion.groupby("promotion_code").agg(
total_promo_sales = ("sales_qty", "sum")
)
promotion_sales.total_promo_sales.sum() # output 394
promotion.sales_qty.sum() # output 466
这个差异的原因是缺少促销代码值(即None
)。由于某种原因,一些促销代码值未被记录。
groupby
函数默认忽略缺失值。要包含它们在计算中,你需要将dropna
参数设置为False
。
promotion.groupby("promotion_code", dropna=False).agg(
total_promo_sales = ("sales_qty", "sum")
)
# output
promotion_code total_promo_sales
A1 122
A2 168
B1 104
NaN 72
我们的示例DataFrame只有10行,所以我们能够注意到缺失值。然而,你可能会处理更大的DataFrame(数千或数百万行),这样就不可能进行视觉检查了。
始终牢记缺失值并检查它们。
我们要谈论的第二个悄悄错误是链式索引。
在Pandas的DataFrame上进行索引非常有用,主要用于获取和设置数据的子集。
我们可以使用行和列标签以及它们的索引值来访问特定的行和标签集。
考虑我们之前示例中的促销DataFrame。假设我们想要更新第二行的销售数量值。下面是一种做法:
promotion["sales_qty"][1] = 45
我们首先选择销售数量列,然后选择索引(也是标签)为1的第二行。这被称为“链式索引”,应该避免使用。
当你执行这行代码时,你会得到一个SettingWithCopyWarning
。操作按预期执行(即值更新为45),但我们不应该忽视这个警告。
根据Pandas文档,“分配给链式索引的乘积具有内在的不可预测的结果”。主要原因是我们无法确定索引操作是否会返回视图或副本。因此,我们尝试更新的值可能会更新,也可能不会更新。
进行此操作的更好(且有保证的)方法是使用loc
方法,它保证直接在DataFrame上执行操作。
这是如何更新销售数量列的第二行值:
promotion.loc[1, "sales_qty"] = 46
第三个悄悄错误与loc
和iloc
方法之间的差异有关。这些方法用于从DataFrame中选择子集。
loc
:按行和列的标签进行选择iloc
:按行和列的位置进行选择默认情况下,Pandas将整数值(从0开始)分配为行标签。因此,行标签和索引值变得相同。
让我们在我们的促销DataFrame上做一个简单的示例。虽然它很小,但足够演示我即将解释的问题。
考虑一个需要选择前4行的情况。这是如何使用iloc
方法来执行的:
promotion.iloc[:4, :]
# output
promotion_code sales_qty price
0 A2 34 24.5
1 A1 32 33.1
2 A2 26 64.9
3 B1 71 52.0
逗号前面的部分确定要选择的行,逗号后面的部分是用于选择列的(“:”表示所有列)。
现在让我们使用loc
方法执行相同的操作。由于行标签和索引值是相同的,我们可以使用相同的代码(只需将iloc
更改为loc
)。
promotion.loc[:4, :]
# output
promotion_code sales_qty price
0 A2 34 24.5
1 A1 32 33.1
2 A2 26 64.9
3 B1 71 52.0
4 A2 44 29.0
嗯,输出不一样。当我们使用loc
方法时,我们多了一行。
原因是使用loc
方法时,上限是包含的,因此最后一行(具有标签4的行)被包括在内。
当使用iloc
方法时,上限是不包含的,因此索引为4的行不包括在内。
这可能是一个小差异,但肯定会导致意外结果,并具有误导你的分析的潜力。
loc
和iloc
方法对许多任务非常有用,但你应该了解它们之间的差异。
引发错误的错误是重要的,但我们需要立即采取必要措施来修复它们。
更阔怕的是未知的错误。它们往往会引起间接效应和其他隐患。在本文中,我们学习了三种这样的情况。
感谢阅读。愿你学有所获!
✄-----------------------------------------------看到这里,说明你喜欢这篇文章,请点击「在看」或顺手「转发」「点赞」。
欢迎微信搜索「panchuangxx」,添加小编磐小小仙微信,每日朋友圈更新一篇高质量推文(无广告),为您提供更多精彩内容。
▼ ▼ 扫描二维码添加小编 ▼ ▼