Pandas Dataframe:将对角子框缩减为单行或如何逐步填充Dataframe
在一个客户端/服务器应用中,客户端会向服务器请求数据,然后根据请求的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把这些序列合并成一个数据框。