如何从pandas DataFrame创建可复制粘贴的文本,以重新创建相同的DataFrame,包括索引?

eh57zj3b  于 2023-10-14  发布在  其他
关注(0)|答案(3)|浏览(101)

动机:

我有一个包含一些数据的CSV,然后将其加载到pandas DataFrame raw_data中。在单元测试时,我想在raw_data上进行一些聚合或其他过程,以创建一个新的DataFrame df,然后确认结果(即df)是我所期望的。
这意味着我需要在单元测试中指定结果应该是什么样的,包括索引。由于我必须经常这样做,所以手动创建样本进行测试是很乏味的。我想做的是,在交互式会话中,构造正确的结果框架,然后将其转换为可以粘贴到测试模块中的内容。
换句话说,我想要一些函数f和反函数F,这样f(df)是我可以复制和粘贴的,而F(f(df)) == df

示例

df = pd.DataFrame({
    'foo': [1, 2, 3],
    'bar': ['a', 'b', 'c'],
    'baz': ['d', 'e', 'f'],
    'qux': ['z', 'y', 'x']
}).set_index(['baz', 'qux'])

我想做的是获取df,获取一些我可以复制并粘贴到我的测试模块中的东西,并创建df的精确副本。
我已经尝试了to_dictto_json,但是对于orient的所有值,要么有一个异常,要么索引没有正确地重新创建(通常,索引的 * 名称 * 被遗漏了)。
下面的代码可以证实这一点:

to_dict

orientations = ['dict', 'split', 'series', 'records', 'list', 'index']

print('\t'.join(['orient', 'eqval', 'valexc', 'eqidx', 'idxexc']))

for orient in orientations:
    try:
        # Convert df to a dict, which I can __repr__ and then copy and paste
        serialized_df = df.to_dict(orient=orient)
        # Then, in theory I should be able to recreate the original df from
        # the dictionary object
        ser_de_df = pd.DataFrame.from_dict(serialized_df, orient=orient)
        
        equal_values = df.equals(ser_de_df)
        values_exception = False
    except:
        equal_values = False
        values_exception = True
        
    try:
        equal_index = df.index.equals(ser_de_df.index) and df.index.names == ser_de_df.index.names
        index_exception = False
    except:
        equal_index = False
        index_exception = True
        
    print('\t'.join(map(str, [orient, equal_values, values_exception, equal_index, index_exception])))

这产生:

orient  eqval   valexc  eqidx   idxexc
dict    False   True    False   False
split   False   True    False   False
series  False   True    False   False
records False   True    False   False
list    False   True    False   False
index   True    False   False   False

因此,orient='index'创建了一个相等值的DataFrame,但索引丢失了名称。

JSON

下面的代码用于确认orient的值不适用于JSON:

orientations = {'split', 'records', 'index', 'columns', 'values', 'table'}

print('\t'.join(['orient', 'eqval', 'valexc', 'eqidx', 'idxexc']))

for orient in orientations:
    try:
        # Convert to JSON, which I could just copy and paste as a string
        serialized_df = df.to_json(orient=orient)
        # Load back into a DataFrame
        ser_de_df = pd.read_json(serialized_df, orient=orient)
        
        equal_values = df.equals(ser_de_df)
        values_exception = False
    except:
        equal_values = False
        values_exception = True
        
    try:
        equal_index = df.index.equals(ser_de_df.index) and df.index.names == ser_de_df.index.names
        index_exception = False
    except:
        equal_index = False
        index_exception = True
        
    print('\t'.join(map(str, [orient, equal_values, values_exception, equal_index, index_exception])))

生产:

orient  eqval   valexc  eqidx   idxexc
columns False   False   False   False
table   True    False   True    False
index   False   False   False   False
split   False   True    False   False
records False   False   False   False
values  False   False   False   False

所以table创建相等的值,但不是相等的索引。
当然,我可以手动添加代码来再次正确设置索引名称,但似乎很奇怪,没有一种方法可以一致地序列化DataFrame,包括完整的索引(除了to_pickle等文件)。
有更好的办法吗?

注:编辑以修复代码中的一个错字,这使我无法找到答案(我在下面添加了答案)。把这个问题放在这里,以防其他人也有同样的问题

xyhw6mcr

xyhw6mcr1#

老实说,我浏览了你写的东西,因为我希望(手指交叉)简单的答案是df.to_clipboard()。这将复制该框架。你可以把它和df = pd.read_clipboard()配对。

z9gpfhce

z9gpfhce2#

我的原始代码中有一个错别字,这掩盖了to_json(orient='table')可以工作的事实:

ser_de_df = pd.read_json(df.to_json(orient='table'), orient='table')

这将同时保留索引标签和名称。
对于一个简洁的Python对象,你可以这样做:

import json

obj = json.loads(df.to_json(orient='table'))

如果你打印或repr obj,你会得到:

{'schema': {'fields': [{'name': 'baz', 'type': 'string'},
   {'name': 'qux', 'type': 'string'},
   {'name': 'foo', 'type': 'integer'},
   {'name': 'bar', 'type': 'string'}],
  'primaryKey': ['baz', 'qux'],
  'pandas_version': '0.20.0'},
 'data': [{'baz': 'd', 'qux': 'z', 'foo': 1, 'bar': 'a'},
  {'baz': 'e', 'qux': 'y', 'foo': 2, 'bar': 'b'},
  {'baz': 'f', 'qux': 'x', 'foo': 3, 'bar': 'c'}]}

然后可以复制和粘贴它,然后使用以下命令将其制作回一个嵌套框架:

pd.read_json(json.dumps({'schema': {'fields': [{'name': 'baz', 'type': 'string'},
   {'name': 'qux', 'type': 'string'},
   {'name': 'foo', 'type': 'integer'},
   {'name': 'bar', 'type': 'string'}],
  'primaryKey': ['baz', 'qux'],
  'pandas_version': '0.20.0'},
 'data': [{'baz': 'd', 'qux': 'z', 'foo': 1, 'bar': 'a'},
  {'baz': 'e', 'qux': 'y', 'foo': 2, 'bar': 'b'},
  {'baz': 'f', 'qux': 'x', 'foo': 3, 'bar': 'c'}]}
), orient='table')
toe95027

toe950273#

to_dict()提供的便利性相比,丢失索引名称似乎是一个小缺点,并且知道如果索引名称很重要,那么您所需要的就是第二个副本pasta: 

df.to_dict() # copy the output

new_df = pd.DataFrame(…) # paste the output, no need for from_dict
new_df.index.name = … # copy and paste the index name

相关问题