Pandas Dataframe:将对角子框缩减为单行或如何逐步填充Dataframe

2 投票
1 回答
919 浏览
提问于 2025-04-18 06:56

在一个客户端/服务器应用中,客户端会向服务器请求数据,然后根据请求的ID来处理服务器返回的回复:

--> Request data for item i using request_id 1
--> Request data for item j using request_id 2
:
<-- Data element i.p for request_id1
<-- Data element j.p for request_id2
<-- Data element i.q for request_id1
<-- Data element j.q for request_id2
<-- Data element i.r for request_id1
<-- Data element j.r for request_id2

这些返回的数据块会被添加到一个字典列表中,下面的代码模拟了这个过程:

import pandas
import random

md = list()
md.append({'request_id': 1, 'p': random.random()})
md.append({'request_id': 2, 'p': random.random()})
md.append({'request_id': 1, 'q': random.random()})
md.append({'request_id': 2, 'q': random.random()})
md.append({'request_id': 1, 'r': random.random()})
md.append({'request_id': 2, 'r': random.random()})

df = pandas.DataFrame(md).set_index('request_id')

print df

当从这个字典列表创建一个数据框(dataframe)时,每一行只有一列有值,其他的都是NaN(表示没有值)。上面的代码会产生以下结果:

                   p         q         r
request_id                              
1           0.955755       NaN       NaN
2           0.920858       NaN       NaN
1                NaN  0.583634       NaN
2                NaN  0.456644       NaN
1                NaN       NaN  0.198991
2                NaN       NaN  0.774762

[6 rows x 3 columns]

我该如何将数据框简化为每个请求ID只保留一行呢?我真正需要的是这样的结果:

                   p         q         r
request_id                              
1           0.955755  0.583634  0.198991
2           0.920858  0.456644  0.774762

[2 rows x 3 columns]

这些数据块的到达顺序是随机的,并且每个请求都会收到一个请求结束的消息。可以保证每个数据块只会发送一次(如果有的话),因此每一行只有一个(或零个)数据元素不是NaN。

一个典型的应用场景是异步获取期权链的数据,其中包含每个期权的各种数据元素,比如价格、隐含波动率(IV)、德尔塔(Delta)、伽马(Gamma)、Theta、维加(Vega)等。

1 个回答

2

也许你可以考虑把md改成一个字典里面再嵌套字典,而不是用字典的列表:

import pandas
import random
import collections

md = collections.defaultdict(dict)
md['p'][1] = random.random()
md['p'][2] = random.random()
md['q'][2] = random.random()
md['q'][1] = random.random()
md['r'][1] = random.random()
md['r'][2] = random.random()

df = pandas.DataFrame(md)
df.index.name = 'request_id'

print df

这样会得到类似下面的结果:

                   p         q         r
request_id                              
1           0.127898  0.565351  0.966917
2           0.983144  0.593652  0.617639

[2 rows x 3 columns]

虽然创建一个大的数据框(DataFrame)然后再缩小它的做法效率不高,但如果你必须使用字典的列表,你可以这样合并行:

import pandas as pd
import random

md = list()
md.append({'request_id': 1, 'p': random.random()})
md.append({'request_id': 2, 'p': random.random()})
md.append({'request_id': 1, 'q': random.random()})
md.append({'request_id': 2, 'q': random.random()})
md.append({'request_id': 1, 'r': random.random()})
md.append({'request_id': 2, 'r': random.random()})
df = pd.DataFrame(md).set_index('request_id')
df = pd.concat([df[col].dropna() for col in df.columns], axis=1)
print(df)

这个方法会去掉每一列中的空值(NaN),然后使用pd.concat把这些序列合并成一个数据框。

撰写回答