如何将两个pandas数据帧与条件组合?

时间:2016-12-02 03:17:54

标签: python pandas dataframe merge dask

我有两个pandas数据框,我想与规则结合。

这是第一个数据帧

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
....

第二个数据框只有两列,rankstart

df2

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

在第一个数据框df1中,数据包含beginend。我想检查df2中的开始整数是否在此范围内。

以下是最终结果:

result

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

start==31333位于31293范围31435df1之间label = label2。整数31434也在31293:31435范围之间,因此它也会使用label2进行注释。值33039不在df2中的任何时间间隔之间,因此它获得NaN值。

组合这些数据帧的规则是:

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

但是,每行必须匹配相同的等级值,例如对于此条件,每行必须与第一个或第二个字符串匹配。

以下是我用来组合这两个数据帧的代码,但它根本没有很好地扩展:

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

还有另一种方法可以通过合并(可能是排名)来做到这一点吗?还有其他任何基于熊猫的解决方案吗?

2 个答案:

答案 0 :(得分: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)

希望这有帮助

答案 1 :(得分: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落在多个beginend对范围内的情况:在这种情况下,您将获得尽可能多的行数匹配标签。

如果您无法将其纳入内存,则可以尝试按 rank对数据进行分区:对于rank == 'first',然后是rank == 'second'的人,请执行此操作等等。 beginendstartdf = df2[(df2.start > 31000) & (df2.start <= 32000)].merge(df1[(df1.begin > 31000) & (df1.end <= 32000)], how = 'left'),例如。