基于三列内容,将一个Pandas数据帧中的行匹配到另一个数据帧中。

15

我有两个Pandas数据帧,一个相当大(30000+行),另一个要小得多(100+行)。

dfA看起来像这样:

      X     Y    ONSET_TIME    COLOUR 
0   104    78          1083         6    
1   172    78          1083        16
2   240    78          1083        15 
3   308    78          1083         8
4   376    78          1083         8
5   444    78          1083        14
6   512    78          1083        14
... ...   ...           ...       ...

dfB的样子大致是这样的:

    TIME     X     Y
0      7   512   350 
1   1722   512   214 
2   1906   376   214 
3   2095   376   146 
4   2234   308    78 
5   2406   172   146
...  ...   ...   ...  
对于dfB中的每一行,我想要找到在dfA中X和Y列的值相等并且是dfB['TIME']大于dfA['ONSET_TIME']的第一行,并返回此行dfA['COLOUR']的值。
dfA表示显示器的刷新,其中X和Y是显示器上物品的坐标,并且为每个不同的ONSET_TIME重复自己(每个ONSET_TIME有108个坐标对)。
在两个数据框中,将有多行X和Y相等,但我需要匹配时间的那一行。
我已经使用for循环和if语句完成了这项工作,只是为了看看它是否能够完成,但显然,考虑到数据框的大小,这需要非常长的时间。
for s in range(0, len(dfA)):
    for r in range(0, len(dfB)):
        if (dfB.iloc[r,1] == dfA.iloc[s,0]) and (dfB.iloc[r,2] == dfA.iloc[s,1]) and (dfA.iloc[s,2] <= dfB.iloc[r,0] < dfA.iloc[s+108,2]):
            return dfA.iloc[s,3]
2个回答

7

可能有更高效的方法来完成这个任务,但是下面提供一种不需要使用慢速for循环的方法:

import pandas as pd

dfB = pd.DataFrame({'X':[1,2,3],'Y':[1,2,3], 'Time':[10,20,30]})
dfA = pd.DataFrame({'X':[1,1,2,2,2,3],'Y':[1,1,2,2,2,3], 'ONSET_TIME':[5,7,9,16,22,28],'COLOR': ['Red','Blue','Blue','red','Green','Orange']})

#create one single table
mergeDf = pd.merge(dfA, dfB, left_on = ['X','Y'], right_on = ['X','Y'])
#remove rows where time is less than onset time
filteredDf = mergeDf[mergeDf['ONSET_TIME'] < mergeDf['Time']]
#take min time (closest to onset time)
groupedDf = filteredDf.groupby(['X','Y']).max()

print filteredDf

 COLOR  ONSET_TIME  X  Y  Time
0     Red           5  1  1    10
1    Blue           7  1  1    10
2    Blue           9  2  2    20
3     red          16  2  2    20
5  Orange          28  3  3    30


print groupedDf

COLOR  ONSET_TIME  Time
X Y                          
1 1     Red           7    10
2 2     red          16    20
3 3  Orange          28    30

基本思路是将两个表合并,这样你就可以在一个表中将时间放在一起。然后,我筛选出最大的记录(最接近你 dfB 上的时间)。如果你对此有疑问,请告诉我。


非常有帮助,谢谢。不过我发现你的最终groupedDf缺少了一些原始DfB中的值。我尝试了:filteredDF.sort('ONSET_TIME').groupby(['DfB_INDEX'], as_index = False).max()据我所知,这给了我我要找的值。 - Alex M-R

2
使用merge()方法 - 它的作用类似于SQL中的JOIN操作 - 您就完成了第一部分。
d1 = '''      X     Y    ONSET_TIME    COLOUR 
   104    78          1083         6    
   172    78          1083        16
   240    78          1083        15 
   308    78          1083         8
   376    78          1083         8
   444    78          1083        14
   512    78          1083        14
   308    78          3000        14
   308    78          2000        14''' 


d2 = '''    TIME     X     Y
      7   512   350 
   1722   512   214 
   1906   376   214 
   2095   376   146 
   2234   308    78 
   2406   172   146'''

import pandas as pd
from StringIO import StringIO

dfA = pd.DataFrame.from_csv(StringIO(d1), sep='\s+', index_col=None)
#print dfA

dfB = pd.DataFrame.from_csv(StringIO(d2), sep='\s+', index_col=None)
#print dfB

df1 =  pd.merge(dfA, dfB, on=['X','Y'])
print df1

结果:

     X   Y  ONSET_TIME  COLOUR  TIME
0  308  78        1083       8  2234
1  308  78        3000      14  2234
2  308  78        2000      14  2234

然后,您可以使用它来过滤结果。
df2 = df1[ df1['ONSET_TIME'] < df1['TIME'] ]
print df2

结果:

     X   Y  ONSET_TIME  COLOUR  TIME
0  308  78        1083       8  2234
2  308  78        2000      14  2234

他还希望时间大于开始时间。添加 df = pd.merge(dfA, dfB, on=['X','Y']); df = df[df["ONSET_TIME"] >df["TIME"]] - ZJS
谢谢,我在此期间已经完成了 :) 我逐步完成它 - 测试它 - 并添加到答案中。这样我就学会了 pandas :) - furas

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接