【问题标题】:Match rows in one Pandas dataframe to another based on three columns根据三列将一个 Pandas 数据框中的行与另一行匹配
【发布时间】:2014-07-14 23:00:59
【问题描述】:

我有两个 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]

【问题讨论】:

    标签: python pandas dataframe


    【解决方案1】:

    可能有一种更有效的方法来做到这一点,但这里有一种方法没有那些缓慢的 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() 据我所知,这给了我正在寻找的值。
    【解决方案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
    

    【讨论】:

    • 他还希望时间大于onset_time。添加 df = pd.merge(dfA, dfB, on=['X','Y']); df = df[df["ONSET_TIME"] >df["TIME"]]
    • 谢谢,我同时做到了 :) 我一块一块地做 - 测试它 - 并添加到答案中。这样我就学会了pandas :)
    猜你喜欢
    • 1970-01-01
    • 2019-01-22
    • 2017-02-10
    • 2017-04-24
    • 2019-01-23
    • 2022-12-14
    • 1970-01-01
    • 1970-01-01
    • 2020-04-19
    相关资源
    最近更新 更多