python为pandas df分配值,如果在另一个df中的日期范围之间

时间:2017-05-18 16:49:08

标签: python pandas dataframe

如果日期介于另一个数据框中的两个日期之间,创建新列并分配值的最佳方法是什么?

e.g。

dataframe A    
date          values
2017-05-16      x  
2017-04-12      Y


dataframe B    #df contains dates to use to filter and associated id

start            end           id
2017-05-08     2017-05-18      34
2017-04-24     2017-05-08      33
2017-04-03     2017-04-24      32

期望的结果

dataframe A     
date          values    id
2017-05-16      x       34 
2017-04-12      Y       32

我已经查看了pd.cut,它似乎对我想要的东西不起作用,并且编写一个循环来迭代多个条件的数据帧似乎效率低下。

2 个答案:

答案 0 :(得分:4)

使用IntervalIndex,这是Pandas 0.20.0中的新功能。这看起来仍处于试验阶段,因此其他解决方案可能更可靠。

# Get the 'id' column indexed by the 'start'/'end' intervals.
s = pd.Series(df_b['id'].values, pd.IntervalIndex.from_arrays(df_b['start'], df_b['end']))

# Map based on the date of df_a.
df_a['id'] = df_a['date'].map(s)

结果输出:

        date values  id
0 2017-05-16      x  34
1 2017-04-12      Y  32

或者,如果您不介意更改df_b的索引,您可以直接转换为IntervalIndex

# Create an IntervalIndex on df_b.
df_b = df_b.set_index(['start', 'end'])
df_b.index = pd.IntervalIndex.from_tuples(df_b.index)

# Map based on the date of df_a.
df_a['id'] = df_a['date'].map(df_b['id'])

答案 1 :(得分:2)

这是一个在sql的一个步骤中非常简单的事情的例子,但在Pandas中却没有那么多。因此,条件是我不喜欢这种方法,这就是它。

  1. 进行完整的笛卡尔加入
  2. 过滤到所需的行&列。
  3. _

    # First Full Outer Join Dataframes 
    # (Requires a Common Column in Pandas Unlike SQL)
    df_A['fake key'] = 1
    df_B['fake key'] = 1
    outer_join = pd.merge(df_A, df_B, how='outer', on='fake key')
    
    # Now Filter Back down to Desired Rows/Columns
    desired_rows    = outer_join.query('date < end and date > start')
    desired_columns = ['date', 'values', 'id']
    
    final = desired_rows[desired_columns]
    final
    

    输出:

            date values  id
    0 2017-05-16      x  34
    5 2017-04-12      y  32
    

    让这个答案有些不满意的事情是:

    1. 完整笛卡尔联合的第一步并不能很好地扩展到大数据
    2. 笛卡尔联接需要一个公共列,因此在这种情况下,首先要创建假密钥列(请参阅this github issue