Преобразовать десятичную метку

У меня есть файл CSV с чтением данных, который я хочу прочитать в Python. Я получаю списки, которые содержат строки, такие как "2,5", Сейчас занимаюсь float("2,5") не работает, потому что имеет неправильный десятичный знак.

Как мне прочитать это в Python как 2.5?

8 ответов

Решение

float("2,5".replace(',', '.')) будет делать в большинстве случаев

Если valueбольшое количество и .был использован для тысяч, вы можете:

Замените все запятые для точек: value.replace(",", ".")

Удалить все, кроме последнего пункта: value.replace(".", "", value.count(".") -1)

Вы можете сделать это с учетом местных условий:

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")

Прочтите этот раздел, прежде чем использовать этот метод.

Панды поддерживают это из коробки:

df = pd.read_csv(r'data.csv', decimal=',')

См. http://pandas.pydata.org/pandas-docs/stable/generated/pandas.read_csv.html

Использование регулярных выражений будет более надежным

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 )

Если вы хотите рассматривать более сложные случаи (числа без цифр перед десятичной отметкой для примера), то для вас может представлять интерес регулярное выражение, разработанное для обнаружения всех типов чисел в следующей цепочке:

/questions/47033839/regulyarnoe-vyirazhenie-dlya-sopostavleniya-chisel-s-zapyatyimi-ili-bez-zapyatyih-v-tekste/47033854#47033854

Попробуйте заменить все запятые на десятичные точки:

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

Функция replaceКонечно, работа с любой подстрокой, так как python теперь различает char и string.

Сначала вы должны убедиться, какая локаль использовалась для предоставления номера. Несоблюдение этого правила может привести к случайным проблемам.

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

если точки используются как разделители тысяч, чтобы поменять местами запятые и точки, вы можете использовать третий символ в качестве временного заполнителя, например:

      value.replace('.', '#').replace(',', '.').replace('#', ',')

но, видя, что вы хотите преобразовать в float из строки, вы можете просто удалить любые точки, а затем заменить любые запятые точками

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

ИМО это наиболее читаемое решение

У меня есть приложение (не под моим контролем), в котором входящее денежное значение может быть в любом из двух форматов, по крайней мере, пока мы убеждаем клиента изменить это. При указании одного разделителя возникает двусмысленность: 1039 может означать 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)


Другие вопросы по тегам