将浮点数转换为整数时,pandas四舍五入的问题

38
我有一个带有浮点数索引的pandas DataFrame,我使用它来查找值(类似于字典)。由于浮点数不完全是它们应该乘的值,因此在将其设置为索引之前,我将所有值乘以10并转换为整数.astype(int)。但是,这似乎执行了floor而不是四舍五入。因此,1.999999999999999992被转换为1而不是2。使用pandas.DataFrame.round()方法进行四舍五入也无法避免此问题,因为值仍然存储为浮点数。
最初的想法(显然会引发关键错误)是这样的:
idx = np.arange(1,3,0.001)
s = pd.Series(range(2000))
s.index=idx
print(s[2.022])

尝试将其转换为整数:

idx_int = idx*1000
idx_int = idx_int.astype(int)
s.index = idx_int
for i in range(1000,3000):
    print(s[i])

输出总是有点随机的,因为整数的“真实”值可能略高于或低于所需值。在这种情况下,索引包含两次值1000,不包含值2999。

4个回答

56

你是正确的, astype(int)会向零转换:

“integer”或“signed”:最小有符号整数 dtype

引用自pandas.to_numeric文档(此文档在数字转换的 astype()中链接)。

如果您想要四舍五入,您需要先进行浮点数四舍五入,然后再转换为整数:

df.round(0).astype(int)

根据您的需要使用其他舍入函数。


由于整数的“真实”值可能略高于或低于所需值,因此输出始终有点随机。

浮点数能够表示整数,因此在round(0)之后进行转换是无损且不冒风险的,请在这里查看详情。


你是不是想用 floor 而不是 ceil?(实际上,两者都不对:这是一个截断操作——即它向零舍入,而不是向正无穷大(ceil)或向负无穷大(floor)舍入。) - Mark Dickinson
@MarkDickinson:没错。我在第一个版本中做得正确,但之后将“smallest”与“ceil”混淆了(但实际意思是“floor”)。经过验证,“smallest”指的是朝零方向。谢谢。 - Giacomo Catenazzi
1
另外,如果您担心NaN,可以使用 df.round(0).astype(pd.Int64Dtype()) :) (https://dev59.com/WGEi5IYBdhLWcg3wbr3S) - Tomasz Gandor
@TomaszGandor,使用pd.Int64Dtype()的问题是无法随后使用fillna('')来典型地呈现带有NaN空格的表格。会抛出错误:"TypeError <UI cannot be converted to an IntegerDtype"。有解决方法吗? - alancalvitti
@alancalvitti - 这可能不是正确的方法(为可视化而操纵数据),但是重新转换为 .astype(object).fillna('') 或许可以解决问题。 - Tomasz Gandor

10

如果我理解正确,您只需要执行四舍五入操作,然后将其转换为整数?

s1 = pd.Series([1.2,2.9])
s1 = s1.round().astype(int)

这将产生输出:

0    1
1    3
dtype: int32

3

如果数据框包含数字和非数字值,而您只想处理数字字段:

df = df.applymap(lambda x: int(round(x, 0)) if isinstance(x, (int, float)) else x)

这非常有用,可以将Dataframe中的所有元素四舍五入。 - Carlos AG
select_dtypes是使用列表推导式的替代方案: df.select_dtypes(include=np.number).applymap(lambda x: int(round(x, 0))) - tbrk

1

有可能在数据框中存在 NA 作为浮点类型的情况。因此,另一种解决方案是:df.fillna(0).astype('int')


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接