Питон Панды Десятичный знак ЕС в США
Я переписывал письма о преобразовании десятичных знаков в ЕС и США, это очень помогло, но я все еще чувствую, что мне нужна помощь экспертов. Мои данные взяты из системы ERP с числами в формате, подобном "1'000" 000,32", и я хотел бы просто преобразовать во что-то вроде"1000000.32"для дальнейшей обработки в Пандах.
Мое реальное решение получить формат США, начиная с ЕС, выглядит следующим образом:
...
# read_csv and merge, clean .. different CSV files
# result = merge (some_DataFrame_EU_format, ...)
...
result.to_csv(path, sep';')
result = read_csv(path, sep';', converters={'column_name': lambda x: float(x.replace ('.','').replace(',','.'))})
....
result.to_csv(path, sep';')
У меня было чувство, что это медленный способ изменить "," на "." из-за read_csv и to_csv (и диска..) он был готов попробовать метод.replace непосредственно в DataFrame, чтобы сэкономить время обработки.
Моим первоначальным предположением было что-то вроде ниже (что я красный в другом месте здесь на форуме..):
result['column_name'] = result['column_name'].replace( '.', '')
result['column_name'] = result['column_name'].replace( ',', '.')
result['column_name'] = result['column_name'].astype(float)
Что не сработало и привело к ошибке "Недопустимый литерал для float".
Я так переехал в:
for i in range (0, len(result)):
result.ix[i,'column_name'] = result.ix[i,'column_name'].replace( '.', '')
result.ix[i,'column_name'] = result.ix[i,'column_name'].replace( ',', '.')
result['column_name'] = result['column_name'].astype(float)
Вышеописанное сработало... но с некоторым удивлением оно оказалось примерно в 3 раза медленнее, чем решение read_csv/convertters. Использование ниже помогло в некотором роде:
for i in range (0, len(result)):
result.ix[i,'column_name'] = result.ix[i,'column_name'].replace( '.', '').replace( ',', '.')
result['column_name'] = result['column_name'].astype(float)
Я прочитал прекрасные руководства... и знаю, что read_csv оптимизирован... но на самом деле не ожидал, что красный цикл / запись / чтение / запись будет в три раза быстрее цикла for!!
Как вы думаете, может быть стоит поработать над этим больше? Любое предложение? Или лучше остаться с повторным подходом записи / чтения / записи?
Мой файл составляет около 30 тыс. Строк по 150 столбцов, чтение / запись / чтение (преобразование)/ запись занимает около 18 секунд,.ix для более 52 секунд с циклом первого типа (и 32 с сгруппированным.replace).
Каков ваш опыт конвертации DataFrames из формата EU в США? Какой-то предложенный способ улучшить? Что насчет "картографирования" или "локали"? Могут ли они быть быстрее?
Большое спасибо, Фабио.
PS Я понимаю, что я был "многословен" и не достаточно "питоничен".. извините извините.. я все еще учусь...:-)
3 ответа
На самом деле в read_csv есть тысячи и десятичный параметр (см. Документацию pandas read_csv, но, к сожалению, оба они не работают вместе (см. Проблему: проблема с github)
Огромное спасибо за ваши замечательные предложения и помощь, Энди и Джефф! Вы очень помогли:-)
Сначала я вернулся с редактором к исходным данным. В некоторых из них я видел, что система, вероятно, применила какое-то автоматическое преобразование, поэтому я недавно загрузил тот же набор данных, что и опция "без преобразования", и избегал использовать, например, Excel или другие программы для открытия / сохранения файлов. Я использовал только текстовые редакторы. В этот момент я сделал read_csv более легким без конвертеров и сгруппировал замены, как предложил Джефф.
Реальный регистр немного длиннее, чем приведенный пример, и включает некоторые чередование (пробелы), столбцы del, concat строки, переименование / замену.... Десятичные знаки заменяются на три столбца: USD Sales, Qty, USD_EUR. На их основе рассчитываются продажи в евро и единичные цены в евро. В исходном файле у нас также есть "-", по какой-то другой причине, до того, как обменный курс будет установлен ("-", ""). Результат:
result = pd.read_csv(path, sep=';', thousands = '.')
col = [ 'qty', 'sales', 'rate']
result[col] = result[col].apply(lambda x: x.str.replace(".","").str.replace(",","."))
result['sales_localcurrency'] = abs(result['sales'].astype(float) / result['rate'].astype(float))
result['sales_localcurrency_unit'] = result['sales_localcurrency'] / result['qty'].astype(float)
result.to_csv(path, sep=';')
30 000 x 150 DataFrame обрабатывается менее чем за 15 секунд:-):-), включая все остальные вещи, которые я здесь подробно не описывал (разбор, del, concat, ..). Все что read/write/read/write было удалено из кода, пропуская "конвертеры" во время read_csv.
Спасибо за вашу помощь:-)!
Пока-пока. Фабио.
- -
Создайте фрейм со значением, которое вы указали, и запишите в CSV
In [2]: df = DataFrame("100'100,32",index=range(30000),columns=range(150))
In [3]: df.iloc[0:5,0:5]
Out[3]:
0 1 2 3 4
0 100'100,32 100'100,32 100'100,32 100'100,32 100'100,32
1 100'100,32 100'100,32 100'100,32 100'100,32 100'100,32
2 100'100,32 100'100,32 100'100,32 100'100,32 100'100,32
3 100'100,32 100'100,32 100'100,32 100'100,32 100'100,32
4 100'100,32 100'100,32 100'100,32 100'100,32 100'100,32
In [4]: df.to_csv('test.csv')
Прочитайте это, нет конвертеров
In [5]: df = read_csv('../test.csv',index_col=0)
In [6]: %timeit read_csv('../test.csv',index_col=0)
1 loops, best of 3: 1e+03 ms per loop
In [7]: df
Out[7]:
<class 'pandas.core.frame.DataFrame'>
Int64Index: 30000 entries, 0 to 29999
Columns: 150 entries, 0 to 149
dtypes: object(150)
In [8]: %timeit read_csv('../test.csv',index_col=0)
1 loops, best of 3: 1e+03 ms per loop
Делать подстановку строк столбец за столбцом. Здесь вы можете указать только определенные столбцы, если хотите, выполнив df[[ list of columns ]].apply(.....)
In [9]: df.apply(lambda x: x.str.replace("'","").str.replace(",",".")).astype(float)
Out[9]:
<class 'pandas.core.frame.DataFrame'>
Int64Index: 30000 entries, 0 to 29999
Columns: 150 entries, 0 to 149
dtypes: float64(150)
In [10]: %timeit df.apply(lambda x: x.str.replace("'","").str.replace(",",".")).astype(float)
1 loops, best of 3: 4.77 s per loop
Общее время тени до 6 с
К вашему сведению, есть thousands
отдельный вариант, но не decimal
один.... хм это было бы намного быстрее....