我有两个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
....
第二个数据框只有两列,rank
和start
df2
rank start
first 31333
first 31434
first 33039
first 33123
first 33125
在第一个数据框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
值。
组合这些数据帧的规则是:
(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
还有另一种方法可以通过合并(可能是排名)来做到这一点吗?还有其他任何基于熊猫的解决方案吗?
答案 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
落在多个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')
,例如。