Numpy如何处理大于int64 max的数字?

1wnzp6jl  于 2022-11-29  发布在  其他
关注(0)|答案(3)|浏览(280)

我正在处理一个组织得非常糟糕的数据库。有些CustomerId不知何故比int 64大。下面是一个示例:88168142359034442077.0
为了能够使用这个ID,我需要把它变成一个字符串并去掉小数。我已经尝试使用下面的代码:

testdf = pd.DataFrame({'CUSTID': ['99418675896216.02342351', '88168142359034442077.0213', '53056496953']})
testdf['CUSTID'] = testdf['CUSTID'].astype('float64').astype('int64').astype(str)
testdf.display()

当我使用上面的方法时,我得到一个溢出,然后大于int 64的数字变成负数,如:-9223372036854775808用于88168142359034442077.0213的电话号码
我一直在寻找其他的方法来实现从string到float,然后float到int,最后int再到string的变化。
我尝试的一个方法是不使用astype('int 64'),但它会将输出转换为科学格式,例如:8.816814235903445e+19对于88168142359034442077.0213,除了使用正则表达式删除小数和'e+19',我真的不知道我还能做什么。
如有任何信息,我们将不胜感激。谢谢!

lf5gs5x2

lf5gs5x21#

作为答案发布,因为这变得太大,我相信有进一步的价值
如果这些值是真实的和预期的ID,而不是导入一些文本或二进制格式的错误结果,我会感到非常惊讶
具体来说,创作程序和数据库本身几乎肯定不会对客户标识符使用高内存十进制表示,而是使用“普通”类型,如int 64(如果它们以这种方式表示的话)!
此外,浮点值会使程序面临IEEE 754浮点混淆的问题(参见Is floating point math broken?),这会巧妙地阻碍各种查找和比较,并且通常无法愉快地或一致地表示这些值,因此不太可能有人合理地使用它们
人为的例子

>>> data1 = "111001111001110100110001111000110110110111110101111000111001110110110010110001110110101110110000110010110011110100110010110011110101110001"
>>> data2 = "111000111000110001110110111000110001110100110010110011110101111001110000110011110100110100110100110010110000110111110111101110110000110010110001110011"
>>> for data in (data1, data2):
...     print("".join(chr(eval("0b" + data[block:block+6])) for block in range(0, len(data), 6)))
... 
99418675896216.02342351
88168142359034442077.0213

这是一个很长的机会,但也许是一个公平的怀疑,这可能会发生在

  • 有人正在输入新条目,但还没有客户ID(还没有?)
  • UI编码为仅接受数字字符串
  • 没有其他检查,数据库将该值存储为字符串

您可以尝试对它们进行另一个比较,例如,看看

  • 它们都来自特定用户
  • 它们都来自特定日期
  • 随着时间的推移,字符串表示会变得更长或更短(因为用户变得更懒或不太确定他们是否使用了某个值)
6tqwzwtp

6tqwzwtp2#

testdf['CUSTID']是包含Python字符串对象的pandas.Series对象。对于包含大整数的pandas.Series对象,要使用的最直接的类型是int Python对象(相对于更高效的本地Numpy类型)。您可以将其转换为Decimal类型,以获得非整数部分。可以使用map进行转换:

testdf['CUSTID'] = list(map(int, map(decimal.Decimal, testdf['CUSTID'].to_list())))

这不是很有效,但Unicode字符串对象和大的可变大小的整数对象实际上都是低效的。由于Numpy本身不支持大整数,这当然是最好的选择(尽管人们可能会找到一种比使用十进制包更快的方法来获得非整数部分)。
下面是一个基于字符串的解析方法,虽然速度比较慢,但是它支持非常大的整数,而不需要使用固定大小的十进制精度:

testdf['CUSTID'] = [int(s.split('.')[0]) for s in testdf['CUSTID'].to_list()]
z18hc3ub

z18hc3ub3#

我建议将它们保留为字符串,并在.之后修剪所有内容:

import pandas as pd

testdf = pd.DataFrame({'CUSTID': ['99418675896216.02342351', '88168142359034442077.0213', '53056496953']})
testdf['CUSTID'] = testdf['CUSTID'].apply(lambda s: s[:s.find(".")])
testdf.display()

请注意,您可以替换:lambda s: s[:s.find(".")]与一些不同的东西,但我不会期望任何变化(eidogg. lambda s: s.split(".", 1)[0]lambda s: re.match(r"^(\d+)(?:\.(\d+))?$", s).groups()[0])比这更远。只是测试他们的一些样本输入,看看哪一个最适合你。
或者,您可能希望对带有extract()的Pandas系列使用str方法,即:

testdf['CUSTID'] = testdf['CUSTID'].str.extract(r"^(\d+)(?:\.(\d+))?$")

但我不确定这是否会比前面提到的解决方案更快。
也许使用rstrip()可以更快地实现某些功能,但您的代码不会像上面那样简单,因为您需要以不同于其他代码的方式(no-op)处理没有.的值。

相关问题