Python 从2个数据帧匹配数据

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

场景:继前面的一些问题之后,我现在有了一个生成2个数据帧(出价/出价)的代码

我要做的是:这两个数据帧将日期作为列标题,标识符作为行索引,其他所有数据帧都有数字值。我想匹配日期、标识符、出价和要求,并以如下格式输出到txt:

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