2016-12-02 91 views
0

我有两个熊猫数据框,我想与规则结合使用。如何将两个熊猫数据框与条件结合?

这是第一个数据帧

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==31333df1label = label231435范围31293之间。整数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落在多于一个的范围内和end对:在这种情况下,您将获得与匹配标签相同数量的行。

如果您不能装入内存,您可以尝试通过rank分区数据:只是那些rank == 'first',然后rank == 'second'做到这一点,等等。例如begin,endstartdf = df2[(df2.start > 31000) & (df2.start <= 32000)].merge(df1[(df1.begin > 31000) & (df1.end <= 32000)], how = 'left')

+0

“如果你不能把它放到内存中,你可以尝试按rank排列数据:只对rank =='first',然后rank =='second',等等。你可以说得更详细点吗?你会尝试 'df_rank1 = df.loc [(df.start> = df.begin)&(df.start <= df.end)&(rank =='first',['rank','start', '标签']]' 'result_rank1 = df2.merge(df,how ='left')' 然后将所有这些连接在一起? – EB2127

+0

我已经编辑了我的答案。看看代码是如何工作的,试着用更小的数据子集来运行它,看看每行代码是什么。 –

+0

当使用较小的子集时,例如'rank =='first''等,所需的RAM太大。但是,如果我要实现这一点,我怎么可以使用'for'循环为每个“dataframe子部分”执行这些命令,然后将它们放在一起? – EB2127