2014-10-13 2 views
1

Я пытаюсь присоединиться к двум фреймворкам данных с датами, которые не идеально совпадают. Для данной группы/даты в левом фрейме данных я хочу присоединиться к соответствующей записи из нужного кадра данных с датой перед левым фреймворком данных. Наверное, проще всего показать пример.Присоединение Pandas по дате

df1:

group  date  teacher 
    a  1/10/00  1 
    a  2/27/00  1 
    b  1/7/00   1 
    b  4/5/00   1 
    c  2/9/00   2 
    c  9/12/00  2 

df2:

teacher date hair length 
    1  1/1/00  4 
    1  1/5/00  8 
    1  1/30/00  20 
    1  3/20/00 100 
    2  1/1/00  0 
    2  8/10/00  50 

дает нам:

group  date  teacher hair length 
    a  1/10/00  1   8 
    a  2/27/00  1   20 
    b  1/7/00   1   8 
    b  4/5/00   1   100 
    c  2/9/00   2   0 
    c  9/12/00  2   50 

Edit 1: рубился вместе способ сделать это. В основном я повторяю каждую строку в df1 и выбираю последнюю соответствующую запись в df2. Это безумно медленно, конечно, должен быть лучший способ.

ответ

0

Похоже, самый быстрый способ сделать это, используя sqlite через pysqldf:

def partial_versioned_join(tablea, tableb, tablea_keys, tableb_keys): 

    try: 
     tablea_group, tablea_date = tablea_keys 
     tableb_group, tableb_date = tableb_keys 
    except ValueError, e: 
     raise(e, 'Need to pass in both a group and date key for both tables') 

    # Note: can't actually use group here as a field name due to sqlite 
    statement = """SELECT a.group, a.{date_a} AS {temp_date}, b.* 
        FROM (SELECT tablea.group, tablea.{date_a}, tablea.{group_a}, 
         MAX(tableb.{date_b}) AS tdate 
         FROM tablea 
         JOIN tableb 
         ON tablea.{group_a}=tableb.{group_b} 
         AND tablea.{date_a}>=tableb.{date_b} 
         GROUP BY tablea.{base_id}, tablea.{date_a}, tablea.{group_a} 
         ) AS a 
        JOIN tableb b 
        ON a.{group_a}=b.{group_b} 
        AND a.tdate=b.{date_b}; 
        """.format(group_a=tablea_group, date_a=tablea_date, 
           group_b=tableb_group, date_b=tableb_date, 
           temp_date='join_date', base_id=base_id) 
    # Note: you lose types here for tableb so you may want to save them 
    pre_join_tableb = sqldf(statement, locals()) 
    return pd.merge(tablea, pre_join_tableb, how='inner', 
        left_on=['group'] + tablea_keys, 
        right_on=['group', tableb_group, 'join_date']) 
1

Один из способов сделать это, чтобы создать новый столбец в левом фрейме данных, которая (на дату данной строки в) определить значение, которое ближе всего и раньше:

df1['join_date'] = df1.date.map(lambda x: df2.date[df2.date <= x].max()) 

затем регулярно присоединиться или слияние между 'join_date' слева и 'date' справа будут работать. Вам может потребоваться настроить функцию для обработки значений Null или других угловых случаев.

Это не очень эффективно (вы ищете правильные даты снова и снова). Более эффективный подход состоит в сортировке обоих кадров данных по датам, перебирать кадра данных слева, и потребляют данные из правого фрейма данных руки только до даты, больше:

# Assuming df1 and df2 are sorted by the dates 

df1['hair length'] = 0 # initialize 

r_generator = df2.iterrows() 
_, cur_r_row = next(r_generator) 

for i, l_row in df1.iterrows(): 
    cur_hair_length = 0 # Assume 0 works when df1 has a date earlier than df2 

    while cur_r_row['date'] <= l_row['date']: 
     cur_hair_length = cur_r_row['hair length'] 
     try: 
      _, cur_r_row = next(r_generator) 
     except StopIteration: 
      break 

    df1.loc[i, 'hair length'] = cur_hair_length 
Смежные вопросы