将小数点转换为输入数字的十进制标记

37

我有一个带数据的CSV文件,想要在Python中读取。我获取了包含字符串"2,5"的列表。现在,使用float("2,5")是不起作用的,因为它具有错误的小数标记。

如何将其作为2.5读入Python?


你有没有检查过:http://pypi.python.org/pypi/Babel/0.9.6? - mouad
8个回答

67

您可以以区域设置为基础进行处理:

import locale

# Set to users preferred locale:
locale.setlocale(locale.LC_ALL, '')
# Or a specific locale:
locale.setlocale(locale.LC_NUMERIC, "en_DK.UTF-8")

print locale.atof("3,14")

在使用这个方法之前,请阅读此部分内容。


2
还需注意这样做不是线程安全的:https://dev59.com/ZEvSa4cB1Zd3GeqPgrhT - Haroldo_OK

33

float("2,5".replace(',', '.')) 在大多数情况下可用。

如果value是一个较大的数字,而千位分隔符使用了.,你可以:

将所有的逗号替换为点号:value.replace(",", ".")

移除除最后一个点号以外的所有点号:value.replace(".", "", value.count(".") -1)


30
只是好奇,这是真正的解决方案吗?对我来说看起来很糟糕。 - Andrey Agibalov
10
这不是全球标准。例如,在俄罗斯,逗号是标准,点不被广泛使用。因此,我认为解决这个问题的正确方法是在一定程度上了解文档作者的所在地。另一个问题是——既然我们正在谈论CSV,他们如何使用逗号保存浮点数呢? :-) 3.14是两个整数,而不是浮点数。 - Andrey Agibalov
9
对于使用逗号作为小数分隔符的国家,标准的CSV格式是在CSV文件中使用“;”作为字段分隔符。参考链接为:http://en.wikipedia.org/wiki/Comma-separated_values。 - Lauritz V. Thaulow
35
标准分隔符是逗号。除了美国人和英国人,大家都知道这个常识 :D - Kheldar
4
我想我表达不够清楚。我的观点只是分隔符取决于使用的语言,主要是数字历史上的表示方式。基于英语和拉丁语的语言使用不兼容的系统,这就是为什么英国和前殖民地出现在你的列表中的原因。谢谢! - Kheldar
显示剩余9条评论

29

在pandas中是否有一些现成的命令可以将逗号小数点替换为点小数点(而不是使用某些正则表达式进行暴力替换)? - hhh
没有找到一个。但是用 apply 或 applymap 替换有什么问题吗? - maggie
如果你最终来到这里并尝试将相同的逻辑应用于read_html,如果你不替换thousands的值,可能会出现解析错误,因为它默认为逗号,如果未指定的话。 df = pd.read_csv(r'data.csv', decimal=',', thousands='.') - undefined

8
使用正则表达式将更加可靠。
import re

decmark_reg = re.compile('(?<=\d),(?=\d)')

ss = 'abc , 2,5 def ,5,88 or (2,5, 8,12, 8945,3 )'

print ss
print decmark_reg.sub('.',ss)

结果

abc , 2,5 def ,5,88 or (2,5, 8,12, 8945,3 )
abc , 2.5 def ,5.88 or (2.5, 8.12, 8945.3 )

如果你想处理更复杂的情况(例如小数点前没有数字的数字),我在以下线程中制作的用于检测所有类型数字的正则表达式可能会对你有所帮助:

stackoverflow.com/questions/5917082/regular-expression-to-match-numbers-with-or-without-commas-and-decimals-in-text/5929469


你如何在pandas数据框上执行此操作(而不是字符串)? - hhh

4

尝试将所有的十进制逗号替换为十进制点:

floatAsStr = "2,5"
floatAsStr = floatAsStr.replace(",", ".");
myFloat = float(floatAsStr)

当然,replace函数可以作用于任何子串,因为Python不区分字符和字符串。


16
“str”是一个糟糕的变量名。 - eumiro
1
你说得对,我只是从某个教程页面复制了代码并添加了最后一行... - penelope
4
floatAsStr并没有好到哪里去。:-P - Veky

4
如果使用小数点作为千位分隔符,想要交换逗号和小数点,可以使用第三个符号作为临时占位符,做法如下:
value.replace('.', '#').replace(',', '.').replace('#', ',')

但是,如果您想从字符串转换为浮点数,您可以只需删除任何点,并用点替换任何逗号。

float(value.replace('.', '').replace(',', '.'))

我认为这是最容易理解的解决方案。


4

首先,您必须确保提供数字时使用的语言环境。如果未能这样做,那么肯定会出现随机问题。

import locale

loc = locale.getlocale()  # get and save current locale
# use locale that provided the number;
# example if German locale was used:
locale.setlocale(locale.LC_ALL, 'de_DE')
pythonnumber = locale.atof(value)
locale.setlocale(locale.LC_ALL, loc)  # restore saved locale

1
作为警告,让我引用文档中的话:通常在某个库例程中调用setlocale()是一个不好的想法,因为它会影响整个程序。保存和恢复它几乎同样糟糕:它很昂贵,并且会影响其他线程,在设置被恢复之前运行。 - oglop

1
我有一个应用程序(不在我的控制之下),其中传入的货币值可以是任何两种格式之一,至少在我们说服客户更改此设置之前是这样的。当提供单个分隔符时存在歧义:1,039 可以表示 1.036 或 1036(千位和...),但实际上,由于代表的是货币,超过分隔符后面的2个字符被认为是非小数点位数。
以下是代码:
def tolerant_monetary_float (x, max_decimals = 2):

    num_dot = x.count ('.')
    num_com = x.count (',')
    
    if not num_dot:
        # no dot
        if not num_com:
            # no dot, no comma
            return float (x)

        if num_com > 1:
            # more than one comma
            return float (x.replace (',', ''))

        # 1 comma: its ambiguous: 1,000 can mean 1000 or 1.0
        if len (x) - x.find (',') -1 <= max_decimals:
            # assume the comma is decimal separator
            return float (x.replace (',', '.'))

        # assume comma is thousand separator
        return float (x.replace (',', ''))

    if not num_com:
        # no comma 
        if not num_dot:
            # no dot, no comma
            return float (x)

        if num_dot > 1:
            # more than one dot
            return float (x.replace ('.', ''))

        # 1 dot: its ambiguous: 1.000 can mean 1000 or 1.0
        if len (x) - x.find ('.') -1 <= max_decimals:
            # assume the dot is decimal separator
            return float (x)

        # assume dot is thousand separator
        return float (x.replace ('.', ''))

    # mix of dots and commas
    if num_dot > 1 and num_com > 1:
        return ValueError (f'decimal number cannot have a mix of "," and ".": {x}')

    ix_dot = x.find ('.') 
    ix_com = x.find (',')

    if ix_dot < ix_com:
        # dot is before comma: 1.000,35
        return float (x.replace ('.', '').replace (',', '.'))

    # comma is before dot: 1,000.35
    return float (x.replace (',', ''))


if __name__ == "__main__":
    assert (tolerant_monetary_float ('1') == 1.0)
    assert (tolerant_monetary_float ('1.2345') == 12345.0)
    assert (tolerant_monetary_float ('1.234') == 1234.0)
    assert (tolerant_monetary_float ('1.23') == 1.23)
    assert (tolerant_monetary_float ('1.2') == 1.2)
    assert (tolerant_monetary_float ('1,2345') == 12345.0)
    assert (tolerant_monetary_float ('1,234') == 1234.0)
    assert (tolerant_monetary_float ('1,23') == 1.23)
    assert (tolerant_monetary_float ('1,2') == 1.2)
    assert (tolerant_monetary_float ('1234,5') == 1234.5)
    assert (tolerant_monetary_float ('1.234,5') == 1234.5)
    assert (tolerant_monetary_float ('1,234.5') == 1234.5)
    assert (tolerant_monetary_float ('1,234,567.85') == 1234567.85)
    assert (tolerant_monetary_float ('1.234.567,85') == 1234567.85)



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