当试图与PeriodIndex类型的对象进行比较并随后编写一些涉及它们的数据测试时,我遇到了一些令人困惑的行为.如果能澄清为什么在处理这些声明的方式上存在差异,那就太好了.

> d = {'col1': ['a','b','c'], 'col2':pd.PeriodIndex(data=['2022-01-01','2021-05-01','2020-10-01'], freq='Q')}
> tdf = pd.DataFrame.from_records(data=d)

> print(tdf.dtypes)
col1           object
col2    period[Q-DEC]
dtype: object

> print(tdf.col2[0])
2022Q1
> print(tdf.col2[0] == '2022Q1')
False
> print(tdf[tdf.col1 == 'a'].col2 == '2022Q1')
0    True

> assert tdf[tdf.col1 == 'a'].col2 == '2022Q1', 'doesnt match'
ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().

> assert all(tdf[tdf.col1 == 'a'].col2 == '2022Q1'), 'doesnt match'
# Passes no big deal

以不同的方式访问同一个对象会使比较从False变为True,然后将单个断言包装在all中有助于传递.

推荐答案

在第一种情况tdf.col2[0] == '2022Q1'中,使用Python ==运算符进行比较,当比较Period(pd.Period('2022Q1'))to a string时,结果为False(与2 == '2'产生False的方式相同).

在第二种情况tdf[tdf.col1 == 'a'].col2 == '2022Q1'中,比较使用pandas比较操作的Series to a string,请参见以下调用堆栈:

  ...\lib\site-packages\pandas\core\ops\common.py(70)new_method()
-> return method(self, other)
  ...\lib\site-packages\pandas\core\arraylike.py(40)__eq__()
-> return self._cmp_method(other, operator.eq)
  ...\lib\site-packages\pandas\core\series.py(5623)_cmp_method()
-> res_values = ops.comparison_op(lvalues, rvalues, op)
  ...\lib\site-packages\pandas\core\ops\array_ops.py(269)comparison_op()
-> res_values = op(lvalues, rvalues)
  ...\lib\site-packages\pandas\core\ops\common.py(70)new_method()
-> return method(self, other)
  ...\lib\site-packages\pandas\core\arraylike.py(40)__eq__()
-> return self._cmp_method(other, operator.eq)
  ...\lib\site-packages\pandas\core\arrays\datetimelike.py(1008)_cmp_method()
-> other = self._validate_comparison_value(other)
  ...\lib\site-packages\pandas\core\arrays\datetimelike.py(528)_validate_comparison_value()
-> other = self._scalar_from_string(other)
> ...\lib\site-packages\pandas\core\arrays\period.py(331)_scalar_from_string()
-> return Period(value, freq=self.freq)

如您所见,在执行实际比较之前,字符串'2022Q1' gets converted到a Period,因此Period('2022Q1')Period('2022Q1')的比较是True.

我不确定这种转换是故意行为还是bug.



至于你问题中的断言部分:将一个序列与某物进行比较会得到一个布尔序列.在条件(ifassert)中使用一系列布尔值时,结果必须正好是一个TrueFalse值,而不是一系列TrueFalse值.正如错误消息所说,您需要决定如何将布尔序列减少为单个布尔.在特殊情况下,序列只有一个元素,但它是一个序列,因此存在误差(对于长度为1的序列,如果使用anyall或仅[0],则当然没有区别).

Python相关问答推荐

Pandas 在最近的日期合并,考虑到破产

max_of_three使用First_select、second_select、

PywinAuto在Windows 11上引发了Memory错误,但在Windows 10上未引发

抓取rotowire MLB球员新闻并使用Python形成表格

输出中带有南的亚麻神经网络

从numpy数组和参数创建收件箱

处理带有间隙(空)的duckDB上的重复副本并有效填充它们

聚合具有重复元素的Python字典列表,并添加具有重复元素数量的新键

修复mypy错误-赋值中的类型不兼容(表达式具有类型xxx,变量具有类型yyy)

如何在Python脚本中附加一个Google tab(已经打开)

对象的`__call__`方法的setattr在Python中不起作用'

如何使Matplotlib标题以图形为中心,而图例框则以图形为中心

什么是最好的方法来切割一个相框到一个面具的第一个实例?

多处理队列在与Forking http.server一起使用时随机跳过项目

用渐近模计算含符号的矩阵乘法

将标签移动到matplotlib饼图中楔形块的开始处

当条件满足时停止ODE集成?

如何在一组行中找到循环?

如何在Python中将超链接添加到PDF中每个页面的顶部?

如何在Gekko中处理跨矢量优化