Python 比较两个不重复的数据帧

Python 比较两个不重复的数据帧,python,pandas,Python,Pandas,我有两个类似的结构化数据帧,分别代表两个时间段,比如2020年7月和2020年8月。其中的数据是来自多个公司来源(如CRM和会计应用程序)的预测和/或实现收入数据。这些列包含关于客户、产品、数量、价格、收入、期限等的数据。现在,我想通过比较两个数据框来了解这两个月到几个月之间发生了什么 我试图通过重命名一些列(如quantity、price和revenue)来实现这一点,然后合并客户端、产品和期间的两个数据帧。然后我计算了数量、价格和收入的差额 但是我遇到了一个问题。。。假设一个特定客户与我们签

我有两个类似的结构化数据帧,分别代表两个时间段,比如2020年7月和2020年8月。其中的数据是来自多个公司来源(如CRM和会计应用程序)的预测和/或实现收入数据。这些列包含关于客户、产品、数量、价格、收入、期限等的数据。现在,我想通过比较两个数据框来了解这两个月到几个月之间发生了什么

我试图通过重命名一些列(如quantity、price和revenue)来实现这一点,然后合并客户端、产品和期间的两个数据帧。然后我计算了数量、价格和收入的差额

但是我遇到了一个问题。。。假设一个特定客户与我们签订了合同,在未来两年内每月购买两种特定产品(abc和xyz)。这意味着在我们7月份的预测中,我们可以将这两项作为收入。实际上,与其他合同以及加权管道中的预期收入相比,该列表要长得多

这是从我们特定客户的总预测中提取的一小部分

    Client  Product Period  Stage       Qty Price   Rev
0   A       abc     2020-07 contracted  1   100     100
1   A       xyz     2020-07 contracted  1   50      50
现在假设这个客户要求购买第二个产品xyz,我们得到了另一个合同。而7月份的情况是这样的:

    Client  Product Period  Stage       Qty Price   Rev
0   A       abc     2020-07 contracted  1   100     100
1   A       xyz     2020-07 contracted  1   50      50
2   A       xyz     2020-07 contracted  1   50      50
现在假设一个月后,我们从我们的会计系统中得出了如下的实际收入(因此我们的预测变成了现实):

现在我想通过在重命名一些列后合并两个df来比较它们

def rename_column(df_name, col_name, first_forecast_period):
    col_name = df_name.rename(columns={col_name: col_name + '_' + first_forecast_period}, inplace=True)
    return df_name

rename_column(df_1, 'Stage', '1') 
rename_column(df_1, 'Price', '1')
rename_column(df_1, 'Qty', '1')
rename_column(df_1, 'Rev', '1')
rename_column(df_2, 'Stage', '2') 
rename_column(df_2, 'Price', '2')
rename_column(df_2, 'Qty', '2')
rename_column(df_2, 'Rev', '2')

result_1 = pd.merge(df_1, df_2, how ='outer')
然后通过一些数学计算得出差异:

result_1['Qty_diff'] = result1['Quantity_2'] - result1['Quantity_1']
result_1['Price_diff'] = result1['Price_2'] - result1['Price_1']
result_1['Rev_diff'] = result1['Rev_2'] - result1['Rev_1']
这导致:

    Client  Product Period  Stage_1     Qty_1   Price_1 Rev_1   Stage_2  Qty_2  Price_2 Rev_2   Qty_diff    Price_diff  Rev_diff
 0  A       abc     2020-07 contracted  1       100     100     realised 1      100     100     0           0           0
 1  A       xyz     2020-07 contracted  1       50      50      realised 2      50      100     1           0           50
 2  A       xyz     2020-07 contracted  1       50      50      realised 2      50      100     1           0           50
因此,问题在于,在第三行中,实现的部分被第二次包含。由于预测和现实是一样的,结果应该是:

    Client  Product Period  Stage_1     Qty_1   Price_1 Rev_1   Stage_2  Qty_2  Price_2 Rev_2   Qty_diff    Price_diff  Rev_diff
 0  A       abc     2020-07 contracted  1       100     100     realised 1      100     100     0           0           0
 1  A       xyz     2020-07 contracted  1       50      50      realised 2      50      100     1           0           50
 2  A       xyz     2020-07 contracted  1       50      50      realised 0      0       0       -1          0           -50

因此,我得到的总收入差是100(+50和+50),而不是0(+50和-50)。有没有办法通过合并两个DF来解决这个问题,或者我需要从另一个方向开始思考。如果是这样,那么任何建议都会很有帮助!谢谢。

为了安全起见,您可能应该在两个dfs上获得客户端产品周期的总计。假设df_1中的所有行都是“收缩的”,则可以执行以下操作:

df_1 = (df_1.groupby(['Client', 'Prooduct', 'Period'])
    .agg({'Stage': 'first', 'Qty': sum, 'Price': 'first', 'Rev': sum})
    # if price can vary between rows of the same product-client
    # .agg({'Stage': 'first', 'Qty': sum, 'Price': 'mean', 'Rev': sum})

# same for df_2
现在,您可以将两个dfs与以下内容合并:

df_merged = df_1.merge(df_2)

结果将分别为df_1和df_2的重复列添加后缀,
\u x
\u y

在合并这两个列之前,请考虑分组
df_1
,这样,当您合并时,您将拥有唯一的行:)相同产品的两个不同行的价格是否始终相同?@Roelant:分组可能是一种解决方案,但也可以消除信息。在实际的数据帧中,第二行有“new sales”,第三行有“upsell”作为合同\排序。@RichieV:在这种情况下是的,因为有一个固定价格的已签署合同。但在其他情况下,价格也可能有所不同。例如,一个新的潜在客户将以标准价格包含在销售渠道中,但在合同中可能会以更高或更低的价格结束。请注意,如果您在代码末尾添加groupby,您可以对差异列求和,并按客户产品获得净差,在您的示例中,该值将为零。谢谢。正如我上面所说,它消除了一些信息,但我想一个解决方案,完全解决这一问题可能涉及大量的编码…我理解。这就是为什么包含尽可能小的样本数据很重要,但这仍然代表了问题的全部复杂性。您需要在groupby之后包含.reset_index(),以防止获取具有层次索引的数据帧。然后合并将崩溃。
df_merged = df_1.merge(df_2)