【问题标题】:Compare columns of two dataframes without merging the dataframes比较两个数据框的列而不合并数据框
【发布时间】:2019-03-29 06:12:27
【问题描述】:

我有两个数据框 DF1 和 DF2。

DF1:

StartDate

1/1/2013
2/1/2013
11/1/2014
4/1/2014
5/1/2015

DF2:

EmploymentType        EmpStatus           EmpStartDate

Employee              Active              11/5/2012
Employee              Active              9/10/2012
Employee              Active              10/15/2013
Employee              Active              10/29/2013
Employee              Terminated          10/29/2013
Contractor            Terminated          11/20/2014
Contractor            Active              11/20/2014

我想要 DF2 中的行数,其中就业类型 = 'Employee' 和 EmpStatus = 'Active' 和 EmpStartDate

输出:

Start Date    Count

1/1/2013      2
2/1/2013      2
11/1/2014     4
4/1/2014      4
5/1/2015      4

如何在不合并两个数据框的情况下实现这一点?

我无法合并数据框,因为没有公用键,而且我需要根据条件计算行数,因此我无法在任何临时列上加入数据框,因为我需要避免交叉连接。

【问题讨论】:

    标签: python pandas


    【解决方案1】:

    如果您的数据框太大,您可以使用笛卡尔连接和过滤来做到这一点:

    (df1.assign(key=1)
       .merge(df2.query('EmploymentType == "Employee" and EmpStatus=="Active"').assign(key=1), 
              on='key')
       .query('EmpStartDate <= StartDate')
       .groupby('StartDate')['key'].count())
    

    输出:

    StartDate
    2013-01-01    2
    2013-02-01    2
    2014-04-01    4
    2014-11-01    4
    2015-05-01    4
    Name: key, dtype: int64
    

    详情:

    • 使用query 过滤df2 以包括EmploymentType 和EmpStatus 分别等于 Employee 和 Active。
    • 为每个数据帧分配一个虚拟密钥,并在虚拟密钥上使用merge 创建一个 所有记录的笛卡尔连接。
    • 使用query 将连接结果过滤到仅包含 EmpStartDate 小于或等于 StartDate。
    • 最后,groupby StartDate 和 count

    另外,请注意使用query 是一种快捷方式。如果您的列名包含特殊字符或空格,那么您需要使用布尔索引过滤您的数据框。

    选项 #2:

    pd.merge_asof(df2.query('EmploymentType == "Employee" and EmpStatus == "Active"').sort_values('EmpStartDate'), 
                  df1.sort_values('StartDate'), 
                  left_on='EmpStartDate', 
                  right_on='StartDate', 
                  direction='forward')\
      .groupby('StartDate')['EmploymentType'].count()\
      .reindex(df1.StartDate.sort_values())\
      .cumsum()\
      .ffill()
    

    输出:

    StartDate
    2013-01-01    2.0
    2013-02-01    2.0
    2014-04-01    4.0
    2014-11-01    4.0
    2015-05-01    4.0
    Name: EmploymentType, dtype: float64
    

    详情:

    • 使用pd.merge_asof 将 df2 过滤器向下加入到 df1 到最近 前瞻性日期。

    • groupby 从 df1 加入的开始日期并计数。

    • reindex 结果由 df.startdate 填写缺失/零值 开始日期
    • 使用cumsum 模拟
    • 使用fillna 用以前的总和填充缺失的记录。

    【讨论】:

    • 笛卡尔积会增加行数导致计数不正确。我只想要满足所有 3 个条件的 DF2 的行数。所以我一直在寻找一种方法来比较 2 个数据框的列而不合并它们。我可以过滤掉“EmploymentType 和 EmpStatus 等于 Employee 和 Active”行,但我不确定如何在不合并的情况下比较 2 个数据帧中的日期列。
    • @user3252184 这是另一种不从笛卡尔/交叉连接爆炸记录的方法。
    • 选项 2 有效!!!!但是我没有重新索引就得到了预期的输出。非常感谢斯科特 :)
    【解决方案2】:

     

    def compensation(x):
    return DF2[DF2['EmpStartDate']<x
     and  DF2['EmpStatus']=='Active'].shape[0]
    
    DF1['Count']=DF1['StartDate']
           .apply(lambda x:  
                       compensation(x),axis=1)
    

    该方法是布尔索引和计数行。 https://pandas.pydata.org/pandas-docs/stable/indexing.html

    【讨论】:

    • 鼓励解释你的代码在做什么。
    猜你喜欢
    • 1970-01-01
    • 2017-07-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多