【问题标题】:Matching data from 2 pandas dataframes匹配来自 2 个 pandas 数据帧的数据
【发布时间】:2017-12-27 12:13:36
【问题描述】:

场景:继之前的一些问题之后,我现在有一个代码可以产生 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)

这是我的第一个数据帧之一的 sn-p(询问):

                01/01/2010   02/01/2010   03/01/2010
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

这是我的第二个数据框之一的 sn-p(出价):

                01/01/2010   02/01/2010   03/01/2010
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

我想得到什么(输出到 txt):

AT0000383864    01/01/2010    161.038     160.614
AT0000383864    02/01/2010    161.5676    161.1436
AT0000383864    03/01/2010    161.5772    161.1532
AT0000385745    01/01/2010    109.4322    109.3122

等等。请记住,有些标识符在两个数据帧(出价/要价)中具有相同日期的数据,而有些标识符仅针对其中一个。

【问题讨论】:

  • 发布您的两个数据框的一些示例输出以及您尝试获得的示例结果会很有用。
  • 也许this documentation 可以使用。
  • @James 刚刚将其添加到末尾。
  • @Marein 我一直在尝试我能找到的所有形式的连接、附加和多索引。似乎没有任何效果。

标签: python pandas dataframe


【解决方案1】:

您可以融合数据框以将列还原为行,然后使用项目和日期合并两个数据框。

这是组装您发布的数据框的一些准备工作:

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,我们可以获取列标题并将它们转换为新列的值。例如,以下将item 保留为一列,使用其他列名(日期)作为名为@9​​87654324@ 的新列的值,并将值列重命名为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

【讨论】:

  • 非常感谢您的回答。只有两个问题:考虑到日期的一部分不匹配(在两个数据帧中不同),这项工作是否有效?而在 ask_df = pd.DataFrame(ask_data, columns='item 01/01/2010 02/01/2010 03/01/2010'.split()) 行中,是否需要一一定义列标题?我目前的数据有数千个。把它们都写下来有点不切实际。
  • Q1:仅当日期和项目 ID 相同时才有效。如果您需要匹配不同日期的行,您将需要创建一个新列(可能从日期列派生),该列提供某种与行应如何匹配相对应的值。使用它而不是日期列。
  • Q2:不,您不需要手动组装列标题。这应该在您从 Excel 中读取数据时进行处理。在此示例中,我只是展示了复制您发布的迷你数据框的步骤。
  • 对于第一季度,我知道,我需要某种新的索引来匹配。是否也可以使用带有标识符的系列映射来进行某种(vlookup)?对于 Q2,在这种情况下,我是否将该部分留空?
  • 我不确定你对后续第一部分的意思。对于第二季度,您不会使用pd.DataFrame,而只是使用来自pd.read_excel(...)的代码中的数据框
猜你喜欢
  • 1970-01-01
  • 2017-05-05
  • 1970-01-01
  • 2020-02-07
  • 2018-03-25
  • 2020-05-24
  • 1970-01-01
  • 1970-01-01
  • 2015-10-19
相关资源
最近更新 更多