python - 使用字符串和浮点数字典的 Pandas DataFrame 分配错误?
问题描述
问题
Pandas 似乎支持使用df.loc
将字典分配给行条目,如下所示:
df = pd.DataFrame(columns = ['a','b','c'])
entry = {'a':'test', 'b':1, 'c':float(2)}
df.loc[0] = entry
正如预期的那样,Pandas 根据字典键将字典值插入到相应的列中。打印这个给出:
a b c
0 test 1 2.0
但是,如果您覆盖相同的条目,Pandas 将分配字典键而不是字典值。打印这个给出:
a b c
0 a b c
问题
为什么会这样?
具体来说,为什么这只发生在第二个作业上?所有后续分配都恢复为原始结果,包含(几乎)预期值:
a b c
0 test 1 2
我说几乎是因为dtype
onc
实际上是一个object
而不是float
所有后续结果。
我已经确定,只要涉及字符串和浮点数,就会发生这种情况。如果它只是一个字符串和整数,或者整数和浮点数,你不会发现这种行为。
示例代码
df = pd.DataFrame(columns = ['a','b','c'])
print(f'empty df:\n{df}\n\n')
entry = {'a':'test', 'b':1, 'c':float(2.3)}
print(f'dictionary to be entered:\n{entry}\n\n')
df.loc[0] = entry
print(f'df after entry:\n{df}\n\n')
df.loc[0] = entry
print(f'df after second entry:\n{df}\n\n')
df.loc[0] = entry
print(f'df after third entry:\n{df}\n\n')
df.loc[0] = entry
print(f'df after fourth entry:\n{df}\n\n')
这给出了以下打印输出:
empty df:
Empty DataFrame
Columns: [a, b, c]
Index: []
dictionary to be entered:
{'a': 'test', 'b': 1, 'c': float(2)}
df after entry:
a b c
0 test 1 2.0
df after second entry:
a b c
0 a b c
df after third entry:
a b c
0 test 1 2
df after fourth entry:
a b c
0 test 1 2
解决方案
1.2.4 的行为如下:
empty df:
Empty DataFrame
Columns: [a, b, c]
Index: []
dictionary to be entered:
{'a': 'test', 'b': 1, 'c': 2.3}
df after entry:
a b c
0 test 1 2.3
df after second entry:
a b c
0 a b c
df after third entry:
a b c
0 a b c
df after fourth entry:
a b c
0 a b c
由于轴上没有索引,因此第一次运行df.loc[0]
该函数:_setitem_with_indexer_missing
0
运行此行:
elif isinstance(value, dict):
value = Series(
value, index=self.obj.columns, name=indexer, dtype=object
)
它将变成dict
一个系列,它的行为符合预期。
但是,在将来,由于索引没有丢失(存在索引0
)_setitem_with_indexer_split_path
,所以运行:
elif len(ilocs) == len(value):
# We are setting multiple columns in a single row.
for loc, v in zip(ilocs, value):
self._setitem_single_column(loc, v, pi)
这只是使用来自的每个值压缩列位置dict
:
在这种情况下,这大致相当于:
entry = {'a': 'test', 'b': 1, 'c': float(2.3)}
print(list(zip([0, 1, 2], entry)))
# [(0, 'a'), (1, 'b'), (2, 'c')]
因此,为什么值是键。
出于这个原因,问题并不像看起来那么具体:
import pandas as pd
df = pd.DataFrame([[1, 2, 3]], columns=['a', 'b', 'c'])
print(f'df:\n{df}\n\n')
entry = {'a': 'test', 'b': 1, 'c': float(2.3)}
print(f'dictionary to be entered:\n{entry}\n\n')
df.loc[0] = entry
print(f'df after entry:\n{df}\n\n')
initial df:
a b c
0 1 2 3
dictionary to be entered:
{'a': 'test', 'b': 1, 'c': 2.3}
df after entry:
a b c
0 a b c
如果索引 loc 存在,它将不会转换为系列:它只是使用可迭代的列 locs 压缩。在字典的情况下,这意味着键是包含在框架中的值。
这也可能是为什么只有迭代器返回其值loc
的迭代器才是可接受的赋值左侧参数的原因。
我也同意@DeepSpace的观点,认为这应该作为一个错误提出。
1.1.5 行为如下:
初始分配与 1.2.4 相比没有变化,但是:
dtypes 在这里值得注意:
import pandas as pd
df = pd.DataFrame({0: [1, 2, 3]}, columns=['a', 'b', 'c'])
entry = {'a': 'test', 'b': 1, 'c': float(2.3)}
# First Entry
df.loc[0] = entry
print(df.dtypes)
# a object
# b object
# c float64
# dtype: object
# Second Entry
df.loc[0] = entry
print(df.dtypes)
# a object
# b object
# c object
# dtype: object
# Third Entry
df.loc[0] = entry
print(df.dtypes)
# a object
# b object
# c object
# dtype: object
# Fourth Entry
df.loc[0] = entry
print(df.dtypes)
# a object
# b object
# c object
# dtype: object
他们引人注目的原因是因为当
take_split_path = self.obj._is_mixed_type
是真的。它执行与 1.2.4 中相同的 zip 操作。
但是,在 1.1.5 中,dtypes are all object
sotake_split_path
仅在第一次赋值后才为 false,因为c
is float64
。后续作业使用:
if isinstance(value, (ABCSeries, dict)):
# TODO(EA): ExtensionBlock.setitem this causes issues with
# setting for extensionarrays that store dicts. Need to decide
# if it's worth supporting that.
value = self._align_series(indexer, Series(value))
这自然是dict
正确对齐的。
推荐阅读
- java - 我应该传递什么上下文 WorkManager.getInstance().enqueue() ?(使用 MVVM + 房间数据库 + WorkManager)
- python - 列表字典和元组列表比较
- javascript - 适用于 iOS 和 iPad 的 Safari 上的 AR.js 视频播放问题
- django - Django反向页面对象编号
- google-analytics - Google Analytics 4,查询参数中带有电子邮件 ID 的页面路径的数据删除请求
- cross-validation - mlr3 中的留一法交叉验证
- android - Android SafetyNet Attestation Nonce 问题
- javascript - React-Js - 使用 useEffect 发出 POST 请求和
- java - 在实现相同接口的类之间切换
- python - 大规模替换同义词