Я пытаюсь экспортировать строку CSV в веб-приложение D3, но команда to_csv
настаивает на добавлении завершающего 0 к данным, что препятствует правильному использованию D3.
Вот минимальный пример, иллюстрирующий проблему.
Мой (упрощенный) фрейм данных:
>>> df = pd.DataFrame([['Alex',20.0000, 50.650]],columns=['Name','Age', 'Weight'])
Name Age Weight
0 Alex 20.0 50.65
df['Age']
содержит float
, на что указывает:
>>> df['Age']
0 20.0
Name: Age, dtype: float64
Затем на основе этого отвечать я запускаю .astype(object)
, чтобы получить нужный формат:
>>> df=df.astype(object)
Name Age Weight
0 Alex 20 50.65
Теперь df['Age']
содержит object
без нуля в конце:
>>> df['Age']
0 20
Name: Age, dtype: object
Это то, что я хотел бы экспортировать с помощью to_csv
, но эта команда повторно добавляет конечный 0 к числу, которого я хочу избежать:
>>> df_csv = df.to_csv(sep=',', index = False)
>>> df_csv
'Name,Age,Weight\nAlex,20.0,50.65\n'
Я пытался использовать df_csv = df.to_csv(sep=',', index = False, float_format='%.0f')
на основе этот ответ, но это не работает, потому что в моем фрейме данных есть другие числа с плавающей запятой, для которых я хочу сохранить ненулевые десятичные числа.
Как я могу предотвратить появление этого конечного 0 для чисел без десятичных знаков?
Вы пробовали df['Age'] = df['Age'].astype(int)
это меня заводит
Name Age Weight
0 Alex 20 50.65
преобразование столбца в тип object
по существу позволяет столбцу содержать числа с плавающей запятой, целые числа, строки и т. д. по сравнению с типизированным столбцом, который будет содержать только этот тип.
И преобразовать его в csv:
df_csv = df.to_csv(sep=',', index = False)
'Name,Age,Weight\r\nAlex,20,50.65\r\n'
Спасибо, да, я пробовал это, но мне нужен "пакетный" подход, потому что есть сотни столбцов (некоторые из которых могут быть добавлены третьей стороной в будущем). Поэтому я бы предпочел избегать жесткого кодирования имен отдельных столбцов, что было преимуществом .astype(obj)
. Знаете ли вы, почему тип object
эффективно удаляет конечный 0 в df, но не в результирующем csv?
Вот один из способов, который будет работать, если у вас нет пробелов в столбцах строк.
Используйте to_string()
после astype(object)
вместо to_csv()
. Это сохранит числовые форматы, но в качестве разделителя будут использоваться пробелы. Если у вас нет пробелов ни в одном из других полей, вы можете использовать регулярные выражения для преобразования пробелов в запятые.
import re
df = df.astype(object)
df_string = re.sub(" +", ",", df.to_string(index=False))
print(df_string)
#Name,Age,Weight
#Alex,20,50.65
Теперь напишите df_string
в свой файл:
with open('path/to/some/file.csv', 'w') as f:
f.write(df_string)
Другой способ использования Pandas replace :
df = df.astype(str)
df = df.replace(to_replace = "\.0+$",value = "", regex = True)
Таким образом, вам не нужно импортировать какой-либо дополнительный модуль.
Работает и со строками с пробелами.
На самом деле заменяемая строка должна быть "\.0+$"
, чтобы избежать изменения таких чисел, как 0.0286
.
Я действительно ненавижу это несоответствие между pandas.DataFrame.to_string
и pandas.DataFrame.to_csv
. Однако я спас данные, скопировав их в новый DataFrame с помощью applymap
:
df_fixed = df.applymap(lambda cell: int(cell) if str(cell).endswith('.0') else cell)
>>> df.to_csv()
',Name,Age,Weight\n0,Alex,20.0,50.65\n'
>>> df_fixed.to_csv()
',Name,Age,Weight\n0,Alex,20,50.65\n'
Обратите внимание, что это не работает с большими числами (например, 10 ** 7), потому что оно начнет использовать нотацию e (1e7).
Я должен отметить, что ответы кажутся неправильно отформатированными, возможно, потому, что
d3.js
является одним из тегов. Я пошел дальше и исправил форматирование всех.