将 pandas DataFrame 以 Unicode 格式写入 JSON

49

我正在尝试将一个包含Unicode的pandas DataFrame转换为JSON格式,但是内置的.to_json函数会转义这些字符。我该如何解决这个问题?

示例:

import pandas as pd
df = pd.DataFrame([['τ', 'a', 1], ['π', 'b', 2]])
df.to_json('df.json')

这将会得到:

{"0":{"0":"\u03c4","1":"\u03c0"},"1":{"0":"a","1":"b"},"2":{"0":1,"1":2}}

与期望结果不同之处:

{"0":{"0":"τ","1":"π"},"1":{"0":"a","1":"b"},"2":{"0":1,"1":2}}


我尝试添加了force_ascii=False参数:

import pandas as pd
df = pd.DataFrame([['τ', 'a', 1], ['π', 'b', 2]])
df.to_json('df.json', force_ascii=False)
但是这会导致以下错误:
UnicodeEncodeError: 'charmap' codec can't encode character '\u03c4' in position 11: character maps to <undefined>


我正在使用WinPython 3.4.4.2 64位和pandas 0.18.0。

4个回答

78

将文件的编码设置为utf-8,然后将该文件传递给.to_json函数可以解决问题:

with open('df.json', 'w', encoding='utf-8') as file:
    df.to_json(file, force_ascii=False)

提供正确的:

{"0":{"0":"τ","1":"π"},"1":{"0":"a","1":"b"},"2":{"0":1,"1":2}}
注意:仍需要使用force_ascii=False参数。

由于某些原因,这对我来说并不起作用,所以我所做的是重新加载转储的JSON,eval所需字段,然后再次转储JSON。 - Ayush Mandowara

2

还有另一种方法可以实现相同的功能。由于JSON由键(双引号中的字符串)和值(字符串,数字,嵌套的JSON或数组)组成,并且它非常类似于Python的字典,因此您可以使用简单的转换和字符串操作从Pandas DataFrame获取JSON。

import pandas as pd
df = pd.DataFrame([['τ', 'a', 1], ['π', 'b', 2]])

# convert index values to string (when they're something else - JSON requires strings for keys)
df.index = df.index.map(str)
# convert column names to string (when they're something else - JSON requires strings for keys)
df.columns = df.columns.map(str)

# convert DataFrame to dict, dict to string and simply jsonify quotes from single to double quotes  
js = str(df.to_dict()).replace("'", '"')
print(js) # print or write to file or return as REST...anything you want

输出:

{"0": {"0": "τ", "1": "π"}, "1": {"0": "a", "1": "b"}, "2": {"0": 1, "1": 2}}

更新: 根据@Swier的提示(谢谢),原始数据框中包含双引号的字符串可能会出现问题。 df.jsonify() 会对它们进行转义(即'"a"'将在JSON格式中产生"\\"a\\"")。通过对字符串方法进行小的更新,也可以处理这个问题。完整示例:

import pandas as pd

def run_jsonifier(df):
    # convert index values to string (when they're something else)
    df.index = df.index.map(str)
    # convert column names to string (when they're something else)
    df.columns = df.columns.map(str)

    # convert DataFrame to dict and dict to string
    js = str(df.to_dict())
    #store indices of double quote marks in string for later update
    idx = [i for i, _ in enumerate(js) if _ == '"']
    # jsonify quotes from single to double quotes  
    js = js.replace("'", '"')
    # add \ to original double quotes to make it json-like escape sequence 
    for add, i in enumerate(idx):
        js = js[:i+add] + '\\' + js[i+add:] 
    return js

# define double-quotes-rich dataframe
df = pd.DataFrame([['τ', '"a"', 1], ['π', 'this" breaks >>"<""< ', 2]])

# run our function to convert dataframe to json
print(run_jsonifier(df))
# run original `to_json()` to see difference
print(df.to_json())

输出:

{"0": {"0": "τ", "1": "π"}, "1": {"0": "\"a\"", "1": "this\" breaks >>\"<\"\"< "}, "2": {"0": 1, "1": 2}}
{"0":{"0":"\u03c4","1":"\u03c0"},"1":{"0":"\"a\"","1":"this\" breaks >>\"<\"\"< "},"2":{"0":1,"1":2}}

1
将结果转换为字符串并替换引号,如果文本值中有引号,则会产生无效的JSON。pd.DataFrame([['τ','a',1],['π','this breaks >>"<< ',2]])将产生{"0": {"0": "τ","1": "π"},"1": {"0": "a","1": "this breaks >>"<< "},"2": {"0": 1,"1": 2}} - Swier
1
谢谢@Swier - 我已经更新了我的答案来解决这个问题。 - Lukas

1
这在Mac OS上运行良好。 df.to_json('df.json', force_ascii=False)

是的,它在 macOS 上可以工作,因为操作系统会使用 "UTF-8" 进行输入/输出。问题更多地涉及不想要转义序列,并且在 Windows 上,用户遇到了输入/输出编码问题。 - Andj

-2

我曾经遇到过同样的问题,尽管我没有写入文件。解决方案是将字符串编码为 'utf-8':

df.to_json(force_ascii=False).encode('utf-8')

df.to_json()将数据框写入文件,它没有返回值,因此在那一点上没有字符串可编码。 - Swier
@Swier 你是对的。我编辑了我的回答。 - stackoverflowed

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,