Ale*_*der 23 python json numpy nan
JSON编码器的默认行为是将NaN转换为'NaN',例如json.dumps(np.NaN)导致'NaN'.如何将此"NaN"值更改为"null"?
我试图子类化JSONEncoder并实现default()方法,如下所示:
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]}'
Run Code Online (Sandbox Code Playgroud)
预期结果:'{"a":1,"c":3,"b":2,"e":null,"f":[1,null,3]}'
Ale*_*der 18
这似乎达到了我的目标:
import simplejson
>>> simplejson.dumps(d, ignore_nan=True)
Out[3]: '{"a": 1, "c": 3, "b": 2, "e": null, "f": [1, null, 3]}'
Run Code Online (Sandbox Code Playgroud)
Han*_*ter 15
你可以重写encodePythonJSONEncoder类的方法,预处理obj并替换nan为None(一旦序列化就会变成null)。
这似乎是最直接的方法,因为正如@Gerrat指出的那样,Python JSONEncoderdefault在遇到nan. 即使在调用dump/dumps时,allow_nan=False它也会在给用户“做自己的事情”的机会之前抛出异常。
import math
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 encode(self, obj, *args, **kwargs):
return super().encode(nan2None(obj), *args, **kwargs)
>>> import numpy as np # only needed as example also contains np.nan
>>> 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]}'
Run Code Online (Sandbox Code Playgroud)
simplejson 会在这里做正确的工作,但是还有一个额外的标志值得包含:
尝试使用 simplejson:
pip install simplejson
Run Code Online (Sandbox Code Playgroud)
然后在代码中:
import simplejson
response = df.to_dict('records')
simplejson.dumps(response, ignore_nan=True,default=datetime.datetime.isoformat)
Run Code Online (Sandbox Code Playgroud)
ignore_nan 标志将正确处理所有 NaN --> null 转换
默认标志将允许 simplejson 正确解析您的日期时间。
对于那些使用 Pandas 的人来说,最简单的方法 - 不需要第三方库: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}},
]
})
Run Code Online (Sandbox Code Playgroud)
如果将其转换为字典列表,Pandas 会保留本机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}}
}]
Run Code Online (Sandbox Code Playgroud)
但如果你让 Pandas 将其直接转换为 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}}
}]
Run Code Online (Sandbox Code Playgroud)
请注意,和orient之间的值略有不同。to_dict()to_json()
如果您只是使用列表、字典和标量值,则可以手动转换 NaN:
import math
def to_none(val):
if math.isnan(val):
return None
return val
Run Code Online (Sandbox Code Playgroud)
正如@Gerrat指出的那样,很dumps(d, cls=NanConverter)遗憾,您的钩子无法正常工作。
@Alexander的simplejson.dumps(d, ignore_nan=True)作品,但引入了附加的依赖项(simplejson)。
如果我们引入另一个依赖关系(熊猫):
另一个明显的解决方法是dumps(pd.DataFrame(d).fillna(None)),但是1972年熊猫出版(Pandas issue 1972)指出,这种d.fillna(None)行为将具有不可预测的行为:
请注意,
fillna(None)它等效于fillna(),这意味着未使用value参数。而是使用默认为正向填充的method参数。
因此,改用DataFrame.where:
df = pd.DataFrame(d)
dumps(df.where(pd.notnull(df), None)))
Run Code Online (Sandbox Code Playgroud)| 归档时间: |
|
| 查看次数: |
11361 次 |
| 最近记录: |