#python #pandas #json-normalize
#python #pandas #json-нормализовать
Вопрос:
Я не знаю, почему исходное содержимое id_1 amp; id_2 изменяется при его печати.
У меня есть файл json с именем test_data.json
{
"objects":{
"value":{
"1298543947669573634":{
"timestamp":"Wed Aug 26 08:52:57 0000 2020",
"id_1":"1298543947669573634",
"id_2":"1298519559306190850"
}
}
}
}
Вывод
python test_data.py
id_1 id_2 timestamp
0 1298543947669573632 1298519559306190848 2020-08-26 08:52:57 00:00
Мой код с именемtest_data.py является
import pandas as pd
import json
file = "test_data.json"
with open (file, "r") as f:
all_data = json.loads(f.read())
data = pd.read_json(json.dumps(all_data['objects']['value']), orient='index')
data = data.reset_index(drop=True)
print(data.head())
Как я могу это исправить, чтобы числовые значения интерпретировались правильно?
Комментарии:
1. Используя
python 3.7.4
amp;pandas 0.25.1
Ответ №1:
- Используя
python 3.8.5
иpandas 1.1.1
Текущая реализация
- Сначала код считывает файл и преобразует его из
str
типа вdict
, сjson.loads
with open (file, "r") as f:
all_data = json.loads(f.read())
- Затем
'value'
преобразуется обратно вstr
json.dumps(all_data['objects']['value'])
- Использование
orient='index'
устанавливаетkeys
заголовки столбцов as, аvalues
находятся в строках.- На этом этапе данные также преобразуются в
int
, и значение изменяется. - Я предполагаю, что на этом шаге есть какая-то проблема с преобразованием с плавающей запятой
- На этом этапе данные также преобразуются в
pd.read_json(json.dumps(all_data['objects']['value']), orient='index')
Обновленный код
Вариант 1
- Используйте
pandas.DataFrame.from_dict
, а затем преобразуйте в числовой.
file = "test_data.json"
with open (file, "r") as f:
all_data = json.loads(f.read())
# use .from_dict
data = pd.DataFrame.from_dict(all_data['objects']['value'], orient='index')
# convert columns to numeric
data[['id_1', 'id_2']] = data[['id_1', 'id_2']].apply(pd.to_numeric, errors='coerce')
data = data.reset_index(drop=True)
# display(data)
timestamp id_1 id_2
0 Wed Aug 26 08:52:57 0000 2020 1298543947669573634 1298519559306190850
print(data.info())
[out]:
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 1 entries, 0 to 0
Data columns (total 3 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 timestamp 1 non-null object
1 id_1 1 non-null int64
2 id_2 1 non-null int64
dtypes: int64(2), object(1)
memory usage: 152.0 bytes
Вариант 2
- Используйте
pandas.json_normalize
, а затем преобразуйте столбцы в числовые.
file = "test_data.json"
with open (file, "r") as f:
all_data = json.loads(f.read())
# read all_data into a dataframe
df = pd.json_normalize(all_data['objects']['value'])
# rename the columns
df.columns = [x.split('.')[1] for x in df.columns]
# convert to numeric
df[['id_1', 'id_2']] = df[['id_1', 'id_2']].apply(pd.to_numeric, errors='coerce')
# display(df)
timestamp id_1 id_2
0 Wed Aug 26 08:52:57 0000 2020 1298543947669573634 1298519559306190850
print(df.info()
[out]:
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 1 entries, 0 to 0
Data columns (total 3 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 timestamp 1 non-null object
1 id_1 1 non-null int64
2 id_2 1 non-null int64
dtypes: int64(2), object(1)
memory usage: 152.0 bytes
Комментарии:
1. Спасибо, приятель. Вариант 1 с использованием from_dict работает отлично. Даже .apply(pd.to_numeric, errors=’принудительный’) кажется необязательным для моего случая. Однако я тоже его использовал. Ты спас меня!
Ответ №2:
Это вызвано проблемой 20608 и все еще происходит в текущей версии Pandas 1.2.4.
Вот мой обходной путь, который работает с моими данными даже немного быстрее, чем read_json
:
def broken_load_json(path):
"""There's an open issue: https://github.com/pandas-dev/pandas/issues/20608
about read_csv loading large integers incorrectly because it's converting
from string to float to int, losing precision."""
df = pd.read_json(pathlib.Path(path), orient='index')
return df
def orjson_load_json(path):
import orjson # The builting json module would also work
with open(path) as f:
d = orjson.loads(f.read())
df = pd.DataFrame.from_dict(d, orient='index') # Builds the index from the dict's keys as strings, sadly
# Fix the dtype of the index
df = df.reset_index()
df['index'] = df['index'].astype('int64')
df = df.set_index('index')
return df
Обратите внимание, что мой ответ сохраняет значения идентификаторов, которые имеют смысл в моем случае использования.