Почему pandas.read_json изменяет значение длинных целых чисел?

#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'])
  
 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
  

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