У меня есть фрейм данных, в котором хранится название магазина и количество ежедневных продаж. Я пытаюсь вставить это в Salesforce, используя скрипт Python ниже. Однако я получаю следующую ошибку:
TypeError: Object of type 'int64' is not JSON serializable
Ниже представлен вид фрейма данных.
Storename,Count
Store A,10
Store B,12
Store C,5
Я использую следующий код, чтобы вставить его в Salesforce.
update_list = []
for i in range(len(store)):
update_data = {
'name': store['entity_name'].iloc[i],
'count__c': store['count'].iloc[i]
}
update_list.append(update_data)
sf_data_cursor = sf_datapull.salesforce_login()
sf_data_cursor.bulk.Account.update(update_list)
Получение ошибки, когда выполняется последняя строка выше. Может ли кто-нибудь помочь исправить это? Спасибо..
@TimJohns Пара скобок вокруг числа не делает его кортежем. (34) - это по-прежнему число 34. Но (34,) - это кортеж.
@DyZ Хороший момент, я не осознавал, что круглые скобки с одним аргументом обрабатываются иначе, чем при наличии нескольких аргументов.
@TimJohns Парни не имеют значения. a=34, также является кортежем
Есть открытый отчет об этой проблеме: bugs.python.org/issue24313






json не распознает типы данных NumPy. Преобразуйте номер в Python int перед сериализацией объекта:
'count__c': int(store['count'].iloc[i])
Спасибо большое, дружище!
Другой вариант - при создании фрейма данных использовать dtype=str
Например, если вы загрузили store из файла csv:
import pandas as pd
store = pd.read_csv('store.csv', dtype=str)
Затем все имеет тип str, который можно сериализовать в json.
Это ужасно. Не делай этого. Абсолютный ужасный совет.
Почему? Это допустимый подход, и он также позволяет решить проблему, заключающуюся в том, что иногда int64 недостаточно велик для представления входного числа. Более того, в JSON большие числа также часто представлены в виде строк. Поэтому, если вопрос заключается в том, чтобы просто преобразовать входной CSV в JSON с наименьшим количеством преобразований, сделанных на этом этапе, это хороший подход.
Голосование вниз, потому что этот ответ не преобразуется должным образом в соответствующий тип json. Он просто предлагает хакерское решение, которое потребует дополнительной постобработки после сериализации json.
Вы можете определить свой собственный кодировщик для решения этой проблемы.
import json
import numpy as np
class NpEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, np.integer):
return int(obj)
elif isinstance(obj, np.floating):
return float(obj)
elif isinstance(obj, np.ndarray):
return obj.tolist()
else:
return super(NpEncoder, self).default(obj)
# Your codes ....
json.dumps(data, cls=NpEncoder)
работает, но результат - строка, без слов с форматированными данными
@IvanCamilitoRamirezVerdes Это именно то, что я искал, поэтому мне это очень помогло. Мне также нравится удобочитаемость добавления класса кодирования в функцию json.dumps.
у меня почему-то не сработало ... поддерживает ли это рекурсивные вызовы?
Еще нужно было добавить elif isinstance(obj, np.bool_): return bool(obj)
Это может быть поздний ответ, но недавно я получил ту же ошибку. После долгого серфинга это решение мне помогло.
def myconverter(obj):
if isinstance(obj, np.integer):
return int(obj)
elif isinstance(obj, np.floating):
return float(obj)
elif isinstance(obj, np.ndarray):
return obj.tolist()
elif isinstance(obj, datetime.datetime):
return obj.__str__()
Вызовите myconverter в json.dumps(), как показано ниже.
json.dumps('message', default=myconverter)
или вы можете использовать elif isinstance(obj, (datetime.date, datetime.datetime)): return obj.isoformat()
Я брошу свой ответ кольцу как более стабильную версию отличное решение @Jie Yang.
numpyencoder и его хранилище.
from numpyencoder import NumpyEncoder
numpy_data = np.array([0, 1, 2, 3])
with open(json_file, 'w') as file:
json.dump(numpy_data, file, indent=4, sort_keys=True,
separators=(', ', ': '), ensure_ascii=False,
cls=NumpyEncoder)
Если вы углубитесь в код Хмаллена в файле numpyencoder/numpyencoder.py, вы увидите, что он очень похож на ответ @Jie Yang:
class NumpyEncoder(json.JSONEncoder):
""" Custom encoder for numpy data types """
def default(self, obj):
if isinstance(obj, (np.int_, np.intc, np.intp, np.int8,
np.int16, np.int32, np.int64, np.uint8,
np.uint16, np.uint32, np.uint64)):
return int(obj)
elif isinstance(obj, (np.float_, np.float16, np.float32, np.float64)):
return float(obj)
elif isinstance(obj, (np.complex_, np.complex64, np.complex128)):
return {'real': obj.real, 'imag': obj.imag}
elif isinstance(obj, (np.ndarray,)):
return obj.tolist()
elif isinstance(obj, (np.bool_)):
return bool(obj)
elif isinstance(obj, (np.void)):
return None
return json.JSONEncoder.default(self, obj)
Очень простой кодировщик numpy может достичь аналогичных результатов в более общем плане.
Обратите внимание, что здесь используется класс np.generic (от которого наследуется большинство классов np) и метод a.item().
Если объект для кодирования не является экземпляром numpy, сериализатор json продолжит работу в обычном режиме. Это идеально подходит для словарей с несколькими объектами numpy и некоторыми другими объектами классов.
import json
import numpy as np
def np_encoder(object):
if isinstance(object, np.generic):
return object.item()
json.dumps(obj, default=np_encoder)
Кратко и лаконично.
Это не сработало, когда у меня был массив с нулевой яркостью, такой как np.array(1). Простое исправление: if isinstance(object, (np.generic, np.ndarray))
Если у вас есть эта ошибка
TypeError: Object of type 'int64' is not JSON serializable
Вы можете изменить эти конкретные столбцы с помощью int dtype на float64, например:
df = df.astype({'col1_int':'float64', 'col2_int':'float64', etc..})
Float64 отлично записывается в Google Spreadsheets
Если вы собираетесь сериализовать массив numpy, вы можете просто использовать метод ndarray.tolist().
От numpy docs,
a.tolist()is almost the same aslist(a), except thattolistchanges numpy scalars to Python scalars
In [1]: a = np.uint32([1, 2])
In [2]: type(list(a)[0])
Out[2]: numpy.uint32
In [3]: type(a.tolist()[0])
Out[3]: int
Если у вас есть контроль над созданием DataFrame, вы можете заставить его использовать стандартные типы Python для значений (например, int вместо numpy.int64), установив для dtype значение object:
df = pd.DataFrame(data=some_your_data, dtype=object)
Очевидным недостатком является то, что вы получаете меньшую производительность, чем с примитивными типами данных. Но мне нравится это решение, оно действительно простое и устраняет все возможные проблемы типов. Не надо никаких подсказок ORM или json.
У меня получилось заставить работать с загрузкой дампа.
Код:
import json
json.loads(json.dumps(your_df.to_dict()))
Звонок
rangeподозрительный. Вы беретеlen(store)и оборачиваете его в кортеж, а затем вызываетеrangeдля этого кортежа. Если вы удалите одну скобку, исправит ли это код? То есть попробуйте это:for i in range(len(store)):.