programing

대신 Python JSON 인코더는 NaN을 null로 변환합니다.

telecom 2023. 3. 21. 21:30
반응형

대신 Python JSON 인코더는 NaN을 null로 변환합니다.

JSON으로 변환할 수 있는 임의의 오브젝트(내스트 가능성이 있음)를 수신하기 위해 코드를 쓰고 있습니다.

의 기본 를 Python으로 변환하는 것입니다.NaN 예 , ) 。json.dumps(np.NaN)이 되다NaN 하면 이 '이러다'를 수 있을까요NaN을 매기다null

다음과 같이 메서드를 하위 분류하고 재정의하려고 했습니다.

from json import JSONEncoder, dumps
import numpy as np
    
class NanConverter(JSONEncoder):
    def default(self, obj):
        try:
            _ = iter(obj)
        except TypeError:
            if isinstance(obj, float) and np.isnan(obj):
                return "null"
        return JSONEncoder.default(self, obj)

>>> d = {'a': 1, 'b': 2, 'c': 3, 'e': np.nan, 'f': [1, np.nan, 3]}
>>> dumps(d, cls=NanConverter)
'{"a": 1, "c": 3, "b": 2, "e": NaN, "f": [1, NaN, 3]}'

결과: ★★★★★★★★★★★★★★★★★★★★★★★:'{"a": 1, "c": 3, "b": 2, "e": null, "f": [1, null, 3]}'

이것으로 내 목표는 달성된 것 같다.

import simplejson


>>> simplejson.dumps(d, ignore_nan=True)
Out[3]: '{"a": 1, "c": 3, "b": 2, "e": null, "f": [1, null, 3]}'
  1. @와 같이는 @Gerrat입니다.dumps(d, cls=NanConverter)불행히도 효과가 없을 거야

  2. @Alexander'ssimplejson.dumps(d, ignore_nan=True)하지만, 생깁니다(동작, 「 」simplejson를 참조해 주세요.

다른 의존관계(판다)를 도입하는 경우:

  1. 또 하나의 명백한 해결책은dumps(pd.DataFrame(d).fillna(None)), 그러나 판다들은 1972년 발행한다.d.fillna(None)에는 예측할수 없는 동작이 할 수 없습니다.

    :fillna(None) fillna()이는 값 파라미터가 사용되지 않음을 의미합니다.대신 기본적으로 순방향 채우기인 메서드 매개 변수를 사용합니다.

  2. 대신 신을 .DataFrame.where:

    df = pd.DataFrame(d)
    dumps(df.where(pd.notnull(df), None)))
    

아쉽게도 @Bramar의 제안을 사용해야 할 것 같습니다.당신은 이것을 직접 사용할 수 없을 거예요.Python의 JSON 인코더용 문서에는 다음과 같이 기술되어 있습니다.

지정한 경우 기본값은 직렬화할 수 없는 개체에 대해 호출되는 함수입니다.

의 ★★★★★★★★★★★★★★★★★.NanConverter.defaultPython의 JSON 인코더는 이미 시리얼화 방법을 알고 있기 때문에 메서드는 호출조차 되지 않습니다.np.nan 문구를 추가합니다.알 수 . 몇 가지 로깅/인쇄 문구를 추가합니다.메서드가 호출되지도 않았음을 알 수 있습니다.

는 결국 이 일을 하게 되었다.encode ★★★★★★★★★★★★★★★★★」iterencodeNanConverter ''', '''objnan로로 합니다.None은 (그것은)가 될 이다.null(일본어)

@Gerrat가 지적했듯이 Python JSONncoder는 호출하지 않습니다.default when 를 만났을 때nan★★★★★★★★★★★★★★★★★★★★★★★dump/dumpsallow_nan=False사용자에게 "자신의 일을 할 수 있는" 기회를 주기 전에 예외를 발생시킵니다.

import math
import numpy as np
from json import JSONEncoder, dumps

def nan2None(obj):
    if isinstance(obj, dict):
        return {k:nan2None(v) for k,v in obj.items()}
    elif isinstance(obj, list):
        return [nan2None(v) for v in obj]
    elif isinstance(obj, float) and math.isnan(obj):
        return None
    return obj

class NanConverter(JSONEncoder):
    def default(self, obj):
        # possible other customizations here 
        pass
    def encode(self, obj, *args, **kwargs):
        obj = nan2None(obj)
        return super().encode(obj, *args, **kwargs)
    def iterencode(self, obj, *args, **kwargs):
        obj = nan2None(obj)
        return super().iterencode(obj, *args, **kwargs)

>>> d = {'a': 1, 'b': 2, 'c': 3, 'e': math.nan, 'f': [1, np.nan, 3]}
>>> dumps(d, cls=NanConverter)
'{"a": 1, "b": 2, "c": 3, "e": null, "f": [1, null, 3]}'

여기서 simplejson은 적절한 작업을 수행할 수 있지만 다음과 같은 추가 플래그가 있습니다.

simplejson을 사용해 보십시오.

pip install simplejson

그 후 코드:

import simplejson

response = df.to_dict('records')
simplejson.dumps(response, ignore_nan=True,default=datetime.datetime.isoformat)

ignore_nan 플래그는 모든 NaN --> 늘 변환을 올바르게 처리합니다.

기본 플래그를 사용하면 simplejson이 데이터 시간을 올바르게 구문 분석할 수 있습니다.

팬더 사용

Panda를 사용하는 사용자에게 가장 간단한 방법 - 서드파티 라이브러리가 필요하지 않습니다. df.to_json.NaN 및 기타 Numpy 유형도 네스트 구조로 변환됩니다.

df = pd.DataFrame({
  'words': ['on', 'off'],
  'lists': [
    [[1, 1, 1], [2, 2, 2], [3, 3, 3]],
    [[np.nan], [np.nan], [np.nan]],
  'dicts': [
    {'S': {'val': 'A'}},
    {'S': {'val': np.nan}},
  ]
})

인 판다를 그대로 합니다.nan§:

json.dumps(df.to_dict(orient='record'))

> [{
    "words": "on",
    "lists": [[1, 1, 1], [2, 2, 2], [3, 3, 3]],
    "dicts": {"S": {"val": "A"}}
  },
  {
    "words": "off",
    "lists": [[NaN], [NaN], [NaN]],
    "dicts": {"S": {"val": NaN}}
  }]

팬더에게 직접 JSON 문자열로 변환해 달라고 하면 해결됩니다.

df.to_json(orient='records')

> [{
    "words": "on",
    "lists": [[1,1,1],[2,2,2],[3,3,3]],
    "dicts": {"S":{"val":"A"}}
  },
  {
    "words": "off",
    "lists": [[null],[null],[null]],
    "dicts": {"S":{"val":null}}
  }]

에 주의:orient이 약간 to_dict() ★★★★★★★★★★★★★★★★★」to_json().

표준 라이브러리 사용

목록, 딕트 및 스칼라 값만 사용하는 경우 NaN을 수동으로 변환할 수 있습니다.

import math

def to_none(val):
    if math.isnan(val):
        return None
    return val

다음 예제에서는 nan을 None으로 바꿉니다.

>>> import simplejson
>>> a = {"example": float("nan")} 
>>> a
{'example': nan}
>>> b = simplejson.dumps(a)
>>> b
'{"example": NaN}'
>>> c = simplejson.loads(b, parse_constant=lambda x: None)
>>> c
{'example': None}

다음의 회피책을 사용합니다.

json_constant_map = {
    '-Infinity': float('-Infinity'),
    'Infinity': float('Infinity'),
    'NaN': None,
}

def json_nan_to_none(obj: typing.Any, *, default: typing.Callable = None) -> None:
    # We want to convert NaNs to None and we have to use for now this workaround.
    # We still want an exception for infinity and -infinity.
    # See: https://github.com/python/cpython/pull/13233
    json_string = json.dumps(obj, default=default)
    return json.loads(
        json_string,
        parse_constant=lambda constant: json_constant_map[constant],
    )

사전을 문자열로 직렬화한 다음 "NaN"을 "null"로 바꾼 다음 다시 인코딩할 수 있습니다.

    d = json.dumps(d) # json dump string
    d = d.replace("NaN", "null")
    d = json.loads(d) # json load string

하지만 조심해야 해요.어떤 이유로 "NaN"이 사전 내의 어떤 키 또는 값의 문자열의 일부인 경우, 이 경우 교체 단계에서 추가 관리가 필요합니다.

당신은 simplejson을 사용할 수 있지만 만약 당신이 JSON 모듈만 사용하고 싶다면 나의 트릭은

json.dumps(d).replace(", NaN," , ', "null",')

Python json 표준 라이브러리에서 이를 커스터마이즈할 수 있는 PR이 있지만 아직 Marge되지 않았습니다.

과 같습니다.NaN로로 합니다.None네스트 리스트도 꽤 잘 처리되는 것 같습니다.dicts의 재귀는 자동으로 처리됩니다.

def null_convert(obj):
    if isinstance(obj, dict):
        for i in obj:
            if isinstance(obj[i], float) and np.isnan(obj[i]):
                obj[i]= None
            if isinstance(obj[i], list):
                for j,v in enumerate(obj[i]):
                    if isinstance(v, float) and np.isnan(v):
                        obj[i][j] = None
    return obj

json.loads(json_str, object_hook = null_convert)

@secrigo-silveira가 대답한 것처럼 DataFrame을 dict에서 json으로 브릿지로 사용하는 것은 좋은 방법입니다.pd.to_json()을 사용하는 것이 좋습니다.질문 코드의 예에 코드 예를 추가해 보겠습니다.이것이, 이 대답을 참조하는 사람에게 도움이 될 것으로 기대하고 있습니다.

import pandas as pd
from json import dumps, loads
import numpy as np

d = {'a': 1, 'b': 2, 'c': 3, 'e': np.nan, 'f': [1, np.nan, 3]}
df = pd.DataFrame.from_dict(d, orient='index')
json_result = dumps(loads(df.to_json())['0'])
print(json_result)

>>>{"a": 1, "b": 2, "c": 3, "e": null, "f": [1, null, 3]}

팬더를 이용하고 있는데 플라스크를 통해 JSON을 서비스하고 싶습니다. 쓰면 될 것 요..replace 해결할 수 합니다.

from numpy import nan as np_nan
...
@app.route('/json')
def json_endpoint():
  df = pd.DataFrame(...)
  df = df.replace(to_replace=np_nan, value=None)
  return df.to_dict()

@alexander 유감스럽게도 JSON은 지원하지 않습니다.

np.nan, np.NaN, np.inf,

null만 지원합니다. 매뉴얼을 참조해 주세요.그러나 Python에서는 None 옵션이 있으므로 null 값을 None 키워드로 대체할 수 있습니다.

Python의 데이터 프레임 또는 목록을 JSON으로 변환할 때 발생하는 다른 문제는 numpy datype을 지원하지 않기 때문에 JSON 허용 가능한 데이터 유형으로 변환할 필요가 있다는 것입니다.아래는 같은 해결책입니다.

class CustomJSONizer(json.JSONEncoder):
  def default(self, obj):
      if isinstance(obj, np.integer):
         return int(obj)
      if isinstance(obj, np.floating):
         return float(obj)
      if isinstance(obj, np.ndarray):
         return obj.tolist()
      if isinstance(obj, np.bool_):
         return super().encode(bool(obj))
      return super(CustomJSONizer, self).default(obj)

이 클래스는 JSON 파일을 사용하는 동안 발생할 수 있는 다양한 데이터 유형을 처리하는 사용자 지정 클래스입니다.이걸 부르려면 json.dumps를 사용해야 합니다.

with open('filename.json', 'w', encoding='utf-8') as f:
     f.write(json.dumps(Return_content,cls=CustomJSONizer, ensure_ascii=False))

가장 심플한 솔루션

NaN을 null로 변환하는 재귀 알고리즘


def transform(obj):
    """Function to check the data type to catch NaN and return the null value or return legitimate data type"""
    if isinstance(obj, float) and np.isnan(obj):
        return None
    if isinstance(obj, np.ndarray):
        return obj.tolist()
    if isinstance(obj, np.integer):
        return int(obj)
    if isinstance(obj, np.floating):
        return float(obj)
    return obj


def checking_object(obj):
    """ Take the dictionary element and recursively check inside
    the nested dictionary containing lists or lists containing Dictionary and converts NaN to null"""
    obj = transform(obj)
    if isinstance(obj, dict):
        for key in obj:
            if isinstance(obj[key], list) or isinstance(obj[key], dict):
                obj[key] = checking_object(obj[key])
            else:
                obj[key] = transform(obj[key])
    if isinstance(obj, list):
        for idx, val in enumerate(obj):
            if isinstance(val, list) or isinstance(val, dict):
                obj[idx] = checking_object(val)
            else:
                obj[idx] = transform(val)
    return obj

이 가능합니다.NaN로.null여기 미국에서checking_object기능. transformed_object = checking_object(json_having_NaN)


다음과 같은 서드파티 라이브러리를 설치할 필요가 없습니다.simplejson

언급URL : https://stackoverflow.com/questions/28639953/python-json-encoder-convert-nans-to-null-instead

반응형