Python 从2个数据帧匹配数据
场景:继前面的一些问题之后,我现在有了一个生成2个数据帧(出价/出价)的代码 我要做的是:这两个数据帧将日期作为列标题,标识符作为行索引,其他所有数据帧都有数字值。我想匹配日期、标识符、出价和要求,并以如下格式输出到txt:Python 从2个数据帧匹配数据,python,pandas,dataframe,Python,Pandas,Dataframe,场景:继前面的一些问题之后,我现在有了一个生成2个数据帧(出价/出价)的代码 我要做的是:这两个数据帧将日期作为列标题,标识符作为行索引,其他所有数据帧都有数字值。我想匹配日期、标识符、出价和要求,并以如下格式输出到txt: date 1 identifier 1 bid ask date 1 identifier 2 bid ask date 1 identifier 3 bid ask date 2 identifier 1
date 1 identifier 1 bid ask
date 1 identifier 2 bid ask
date 1 identifier 3 bid ask
date 2 identifier 1 bid ask
date 2 identifier 2 bid ask
date 2 identifier 4 bid ask
date 3 identifier 2 bid ask
date 2 identifier 3 bid ask
等等
Obs1:并非所有日期都具有所有标识符的值(有些是NaN)
Obs2:我已经尝试(在我的代码的早期版本中)拥有数据帧列表或只有两个数据帧(出价和出价),但我一直遇到多个问题(例如:我得到未知值格式或超时),所以我决定将源文件分为两组
问题:我无法正确匹配数据(如vlookup)
问题1:我做错了什么?有更好的办法吗
Obs3:我目前正在尝试使用多索引创建一个更高级别的3d数据帧(出价/出价)。我还尝试使用pandas的series.map函数,在数据帧之间执行某种“vlookup”,但这并不是很有效
当前代码:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import glob, os
import datetime as dt
from datetime import datetime
import matplotlib as mpl
from openpyxl import load_workbook
import sys
directory = os.path.join("C:\\","Users\\DGMS\\Desktop\\final 2\\run 1 test")
dfbid = pd.DataFrame()
dfask = pd.DataFrame()
b = pd.DataFrame()
a = pd.DataFrame()
for root,dirs,files in os.walk(directory):
for file in files:
f = os.path.join(root, file)
wb = load_workbook(f)
print (f)
for sheet in wb.worksheets:
if sheet.title == "Bid":
a = pd.read_excel(f, "Bid")
for i in range(1,len(a.columns)):
a.columns.values[i] = pd.to_datetime(a.columns.values[i])
dfbid = pd.concat([dfbid, a])
print ('bid done')
elif sheet.title == "Ask":
b = pd.read_excel(f, "Ask")
for i in range(1,len(b.columns)):
b.columns.values[i] = pd.to_datetime(b.columns.values[i])
dfask = pd.concat([dfask, b])
print ('ask done')
parts = {'Bid': dfbid, 'Ask': dfask}
finalresult = pd.concat(parts)
这是我的第一个数据帧(ask)的一个片段:
这是我的第二个数据帧(bid)的一个片段:
我试图获取的内容(输出到txt):
等等。请记住,有些标识符在两个数据框(bid/ask)中都有相同日期的数据,有些标识符仅在其中一个数据框中有相同日期的数据。您可以将数据框合并,将列重新拆分为行,然后使用项和日期合并两个数据框 下面是组装您发布的数据框的一些准备工作:
import pandas as pd
ask_str = '''AT0000383864 160.614 161.1436 161.1532
AT0000385745 109.3122 109.3144 109.3068
AT0000386115 117.7972 118.0388 118.051
AT0000A001X2 119.7004 120.0058 120.031
AT0000A04967 152.8196 153.7868 153.792'''
bid_str = '''AT0000383864 161.038 161.5676 161.5772
AT0000385745 109.4322 109.4344 109.4268
AT0000386115 118.0202 118.2618 118.274
AT0000A001X2 119.8284 120.1338 120.159'''
ask_data = [line.split() for line in ask_str.split('\n')]
bid_data = [line.split() for line in bid_str.split('\n')]
ask_df = pd.DataFrame(ask_data, columns='item 01/01/2010 02/01/2010 03/01/2010'.split())
bid_df = pd.DataFrame(bid_data, columns='item 01/01/2010 02/01/2010 03/01/2010'.split())
如果我们使用pd.melt
,我们可以获取列标题并将其转换为新列的值。例如,下文将项
保留为一列,使用其他列名(日期)作为名为date
的新列的值,并将值列重命名为ask
:
pd.melt(ask_df, id_vars='item', var_name='date', value_name='ask')
#returns:
item date ask
0 AT0000383864 01/01/2010 160.614
1 AT0000385745 01/01/2010 109.3122
2 AT0000386115 01/01/2010 117.7972
3 AT0000A001X2 01/01/2010 119.7004
4 AT0000A04967 01/01/2010 152.8196
5 AT0000383864 02/01/2010 161.1436
6 AT0000385745 02/01/2010 109.3144
7 AT0000386115 02/01/2010 118.0388
8 AT0000A001X2 02/01/2010 120.0058
9 AT0000A04967 02/01/2010 153.7868
10 AT0000383864 03/01/2010 161.1532
11 AT0000385745 03/01/2010 109.3068
12 AT0000386115 03/01/2010 118.051
13 AT0000A001X2 03/01/2010 120.031
14 AT0000A04967 03/01/2010 153.792
这是连接两个数据帧所需的数据形式。我们将这两个数据帧融合在一起,将其解压,然后将它们合并到相应的列上
ab_df = pd.merge(pd.melt(ask_df, id_vars='item', var_name='date', value_name='ask'),
pd.melt(bid_df, id_vars='item', var_name='date', value_name='bid'),
how='inner',
on=['item','date'])
现在我们可以按项目排序,然后按日期排序
ab_df.sort_values(['item', 'date'])
#returns:
item date ask bid
0 AT0000383864 01/01/2010 160.614 161.038
4 AT0000383864 02/01/2010 161.1436 161.5676
8 AT0000383864 03/01/2010 161.1532 161.5772
1 AT0000385745 01/01/2010 109.3122 109.4322
5 AT0000385745 02/01/2010 109.3144 109.4344
9 AT0000385745 03/01/2010 109.3068 109.4268
2 AT0000386115 01/01/2010 117.7972 118.0202
6 AT0000386115 02/01/2010 118.0388 118.2618
10 AT0000386115 03/01/2010 118.051 118.274
3 AT0000A001X2 01/01/2010 119.7004 119.8284
7 AT0000A001X2 02/01/2010 120.0058 120.1338
11 AT0000A001X2 03/01/2010 120.031 120.159
发布两个数据帧的一些示例输出以及您试图获得的示例结果将非常有用。也许会有用。@James刚刚在末尾添加了这些内容。@Marein我一直在尝试各种形式的连接、附加和多索引。似乎什么都没用。非常感谢你的回答。只有两个问题:考虑到部分日期不匹配(在两个数据帧中是不同的),这是否有效?在行ask_df=pd.DataFrame(ask_data,columns='item 01/01/2010 02/01/2010 03/01/2010'.split())中,是否需要逐个定义列标题?我目前的数据有上千条。把它们全部写出来有些不切实际。Q1:只有在日期和项目ID相同的情况下,这才有效。如果需要为不同的日期匹配行,则需要创建一个新列(可能来自日期列),该列提供与行匹配方式相对应的某种值。使用它而不是日期列。问题2:不,不需要手动组装列标题。从Excel中读取数据时,应处理此问题。在这个例子中,我只是展示了复制您发布的迷你数据帧的步骤。我知道,对于Q1,我需要某种新的索引来匹配。是否也可以使用带有标识符的序列映射到某种(vlookup)?。对于Q2,在这种情况下,我是否要将该部分留空?我不确定您对后续第一部分的意思。对于第二季度,您不会使用
pd.DataFrame
,而只是使用pd.read\u excel(…)
pd.melt(ask_df, id_vars='item', var_name='date', value_name='ask')
#returns:
item date ask
0 AT0000383864 01/01/2010 160.614
1 AT0000385745 01/01/2010 109.3122
2 AT0000386115 01/01/2010 117.7972
3 AT0000A001X2 01/01/2010 119.7004
4 AT0000A04967 01/01/2010 152.8196
5 AT0000383864 02/01/2010 161.1436
6 AT0000385745 02/01/2010 109.3144
7 AT0000386115 02/01/2010 118.0388
8 AT0000A001X2 02/01/2010 120.0058
9 AT0000A04967 02/01/2010 153.7868
10 AT0000383864 03/01/2010 161.1532
11 AT0000385745 03/01/2010 109.3068
12 AT0000386115 03/01/2010 118.051
13 AT0000A001X2 03/01/2010 120.031
14 AT0000A04967 03/01/2010 153.792
ab_df = pd.merge(pd.melt(ask_df, id_vars='item', var_name='date', value_name='ask'),
pd.melt(bid_df, id_vars='item', var_name='date', value_name='bid'),
how='inner',
on=['item','date'])
ab_df.sort_values(['item', 'date'])
#returns:
item date ask bid
0 AT0000383864 01/01/2010 160.614 161.038
4 AT0000383864 02/01/2010 161.1436 161.5676
8 AT0000383864 03/01/2010 161.1532 161.5772
1 AT0000385745 01/01/2010 109.3122 109.4322
5 AT0000385745 02/01/2010 109.3144 109.4344
9 AT0000385745 03/01/2010 109.3068 109.4268
2 AT0000386115 01/01/2010 117.7972 118.0202
6 AT0000386115 02/01/2010 118.0388 118.2618
10 AT0000386115 03/01/2010 118.051 118.274
3 AT0000A001X2 01/01/2010 119.7004 119.8284
7 AT0000A001X2 02/01/2010 120.0058 120.1338
11 AT0000A001X2 03/01/2010 120.031 120.159