Python 基于三列将一个数据帧中的行与另一个数据帧中的行匹配

Python 基于三列将一个数据帧中的行与另一个数据帧中的行匹配,python,pandas,dataframe,Python,Pandas,Dataframe,我有两个熊猫数据帧,一个很大(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

我有两个熊猫数据帧,一个很大(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
... ...   ...           ...       ...
    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看起来像:

      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
... ...   ...           ...       ...
    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['start_TIME']的第一行,并为这一行返回dfA['color']的值

dfA表示显示器的刷新,其中X和Y是显示器上项目的坐标,因此在每个不同的开始时间重复它们自己(开始时间的每个值有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]
范围(0,len(dfA))内的s的
:
对于范围(0,len(dfB))内的r:
如果(dfB.iloc[r,1]==dfA.iloc[s,0])和(dfB.iloc[r,2]==dfA.iloc[s,1])和(dfA.iloc[s,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
     X   Y  ONSET_TIME  COLOUR  TIME
0  308  78        1083       8  2234
2  308  78        2000      14  2234
然后您可以使用它来过滤结果

df2 = df1[ df1['ONSET_TIME'] < df1['TIME'] ]
print df2

也许有一种更有效的方法可以做到这一点,但这里有一种方法没有那些慢速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
将熊猫作为pd导入
数据帧({'X':[1,2,3],'Y':[1,2,3],'Time':[10,20,30]})
数据帧({'X':[1,1,2,2,2,3],'Y':[1,1,2,2,2,3],'开始时间':[5,7,9,16,22,28],'COLOR':['Red','Blue','Blue','Red','Green','Orange']))
#创建一个表
mergeDf=pd.merge(dfA,dfB,左上=['X','Y'],右上=['X','Y'])
#删除时间小于开始时间的行
filteredDf=mergeDf[mergeDf['start_TIME']

基本的想法是合并两个表,以便将时间放在一个表中。然后我对最大的记录进行筛选(最接近dfB上的时间)。如果您对此有疑问,请告诉我。

他还希望时间大于起始时间。添加df=pd。合并(dfA,dfB,on=['X','Y']);df=df[df[“起始时间”]>df[“TIME”]]谢谢,我同时做到了:)我一件一件地做-测试-并添加到答案中。通过这种方式,我了解了熊猫(pandas)
:)这非常有用,谢谢,尽管我发现您的最终groupedDf缺少原始DfB中的一些值。我尝试了:filteredDF.sort('start_TIME').groupby(['DfB_INDEX'],as_INDEX=False.).max(),这给了我所能找到的值。