2016-12-02 5 views
0

Есть два блока данных pandas, которые у меня есть, которые я хотел бы объединить с правилом.Как объединить два кадра данных pandas с условным?

Это первый dataframe

import pandas as pd 
df1 = pd.Dataframe() 

df1 

rank begin end  labels 
first 30953 31131 label1 
first 31293 31435 label2 
first 31436 31733 label4 
first 31734 31754 label1 
first 32841 33037 label3 
second 33048 33456 label4 
.... 

Второй dataframe только две колонки, rank и start

df2 

rank start 
first 31333  
first 31434  
first 33039  
first 33123  
first 33125  

В первом dataframe df1, данные имеют begin и end. Я хотел бы проверить, находится ли целое число для начала в df2 в этом диапазоне.

Вот конечный результат он должен выглядеть следующим образом:

result 

rank start  labels 
first 31333  label2 
first 31434  label2 
first 33039  NaN 
first 33123  label4 
first 33125  label4 

start==31333 находится в диапазоне между 31293 до 31435 в df1 с label = label2. Целое число 31434 также находится между диапазоном 31293:31435, поэтому оно также аннотируется label2. Значение 33039 не находится между интервалом в df2, поэтому оно получает значение NaN.

правило, с помощью которого объединены эти dataframes заключается в следующем:

(df2.start >= df1.begin) & (df2.start <= df1.end) 

, но и, каждая строка должна соответствовать одинаковые значения ранга, например, каждая строка должна соответствовать первой или второй строке для этого условного выражения.

Вот код, который я использую, чтобы объединить эти два dataframes, но это не очень хорошо масштабируется на всех:

from numpy import nan 

def between_range(row): 
    subset = df1.loc[(row["rank"] == df1.rank) & (row.start >= repeats.start) & (row.start <= repeats.end), :] 
    if subset.empty: 
     return np.nan 
    return subset.labels 

Есть еще один способ сделать это с помощью объединения (возможно, по рангу)? Любое другое решение на основе панд?

+0

@Kartik Я попытался упростить вопрос здесь. Спасибо за любую помощь – EB2127

+0

@MaxU Я обновил выше. Любые идеи, как это может масштабироваться/работать? – EB2127

ответ

1

Попробуйте Этот блок кода

def match_labels(row): 
    curr_df = df1[ (df1['rank']==row['rank']) & (df1['begin']<=row['start']) & (df1['end']>=row['start']) ] 
    try: 
     row['labels'] = curr_df['labels'].iloc[0] 
    except: 
     row['labels'] = np.NaN 

    return row 

result = df2.apply(lambda x:match_labels(x),axis=1) 

Надеется, что это помогает

+0

Спасибо за ответ.Почему это работает, когда мой сценарий выше работает в течение нескольких дней, и ничего не показывать? – EB2127

1

Вы можете сделать все быстро с массивным присоединиться, если вы можете разместить len(df1)*len(df2) строк данных в память:

df = df2.merge(df1, how = 'left') 
df = df.loc[(df.start >= df.begin) & (df.start <= df.end),['rank','start','labels']] # This gives you the correct label of every entry that does indeed belong to a label. 
result = df2.merge(df, how = 'left') # This effectively adds the entries that do not belong to any label back into df. 

Этого решение также заботится о случаях, когда start находится в диапазоне более одного begin и end пар: в таких случаях вы получите столько строк, сколько есть соответствующих меток.

Если вы не можете поместить это в памяти, вы можете попробовать разделение данных по rank: сделать это для тех, кто только с rank == 'first', то rank == 'second', и так далее.begin, end и start: df = df2[(df2.start > 31000) & (df2.start <= 32000)].merge(df1[(df1.begin > 31000) & (df1.end <= 32000)], how = 'left'), например.

+0

«Если вы не можете поместить это в память, вы можете попробовать разбить ваши данные по рангу: сделайте это только для тех, у кого есть ранг == 'first', затем rank == 'second' и т. Д.». Можете быть более конкретными? Вы бы попробовали 'df_rank1 = df.loc [(df.start> = df.begin) & (df.start <= df.end) & (rank == 'first', ['rank', 'start', 'label']] ' ' result_rank1 = df2.merge (df, how = 'left') ' А затем объединить все это вместе в конце? – EB2127

+0

Я сделал редактирование своего ответа. Посмотрите, как работает код, попробуйте запустить его с меньшим подмножеством ваших данных и посмотреть, что делает каждая строка. –

+0

При использовании меньших подмножеств, т. е. 'rank == 'first'' и т. д., требуемая RAM слишком велика Однако, если бы я должен был это реализовать, как я мог бы использовать цикл 'for' для выполнения этих команд для каждого« подкатегории данных », а затем собрать их все вместе? – EB2127

Смежные вопросы