Question: and sorry if this has been asked before (I could only find approaches that worked on previous rows and not the rest of the dataframe.) I'm currently trying to switch out my iterative approach for a problem to a more Pandas (and time) friendly version. The problem is as follows: I have two columns, "A" and "B" that are players. At each time, "A" and "B" take on different arbitrary values. I want to add a third column that has a value either "A wins!" or "B wins!" based on the rows beneath the values at that row. To determine when 'A wins!' for a certain row number, I want to compare the value in column "A" at that row with each value in column 'B' that is beneath this row. To determine when 'B wins!', I want to do the same thing: take the value in row "B" and compare it to each entry in column "A" beneath this entry. Whichever is first to "match" with a value in another column will be the winner. Here's an example:     Time A B Winner     1 2 4 A wins!   2 3 5 B wins!   3 5 2 A wins!   4 6 5 None   5 2 10 B wins!   6 10 7 None     At time 1, A wins because at time 3 "B" takes on the value 2 before "A" can take on 4. At time 2, "B" wins because "A" in the row below takes on the value 5 before "B" took on the value 3. This is similar for time 3 and 5, and at times 4 & 6 there is no winner because the opposing players do not happen to take on each others values in the later rounds. Right now, I have a working solution by just using df.iterrows(). I have a pretty large dataset, so I would like to speed this up but I can't think of any simple Panda's functions because they usually isolate by row. All my attempts of apply and map have not worked because of the dependence on rows, so I'm looking for a solution that might cut down time and not have to use explicit iteration. Any and all help would be appreciated, thank you!! EDIT: Here's my working iterative solution. I feed a DataFrame into find_winner which calls find_winner_row on each row. def find_winner_row(df, row, result): A_val = df['A'][row] # Player A B_val = df['B'][row] # Player B potentials_B = np.where(df['A'][row+1:] == B_val)[0] #[row+1:] slices and only considers the future values of A potentials_A = np.where(df['B'][row+1:] == A_val)[0] # below logic is just to handle the case when there are no matching values if potentials_B.size == 0: B_switch_time = len(df.columns) + 1 else: B_switch_time = potentials_B[0] if potentials_A.size == 0: A_switch_time = len(df.columns) + 1 else: A_switch_time = potentials_A[0] # now which is first? if B_switch_time < A_switch_time: result[row] = "B" elif B_switch_time > A_switch_time: result[row] = "A" else: result[row] = "None" def find_winner(df): result_series = pd.Series(np.zeros(len(df.columns))) for num, (index, row) in enumerate(df.iterrows()): find_winner_row(df, num, result_series) df.loc[:,'Winner'] = result_series.values return df ## So with our given example above, we can run the following and see we get the expected result demo_df = pd.DataFrame([[2,4],[3,5],[5,2],[6,5],[2,10],[10,7]],columns=['A','B']) find_winner(demo_df) 

Answer: Started writing this before you added your code -- but figure it might still be helpful. I was able to write 1 function that, based on the logic, returns a string of who wins based on a row index and given DataFrame with minimal (internal) iteration: # Sample data import pandas as pd data = {"Time":[1,2,3,4,5,6],"A":[2,3,5,6,2,10],"B":[4,5,2,5,10,7],"Winner":["A","B","A","None","B","None"]} df = pd.DataFrame(data) def FindWinner(row_index,dataframe=df): # Record the intial value in indicated column A_initial = df.iloc[row_index]["A"] B_initial = df.iloc[row_index]["B"] # Convert data underneath this row into a pair of lists rowsUnderA = list(df.iloc[row_index+1:]["A"]) rowsUnderB = list(df.iloc[row_index+1:]["B"]) # Use .index() to find when the inital value appears next in the other list try: rowsUntilA_initial = rowsUnderB.index(A_initial) except ValueError: rowsUntilA_initial = "DOES_NOT_APPEAR" try: rowsUntilB_initial = rowsUnderA.index(B_initial) except ValueError: rowsUntilB_initial = "DOES_NOT_APPEAR" # Set win conditions--> first handle scenarios where one or both values do not appear if rowsUntilB_initial == "DOES_NOT_APPEAR" and rowsUntilA_initial == "DOES_NOT_APPEAR": return "No one wins :(" elif rowsUntilB_initial == "DOES_NOT_APPEAR" and rowsUntilA_initial != "DOES_NOT_APPEAR": return "A wins!" elif rowsUntilB_initial != "DOES_NOT_APPEAR" and rowsUntilA_initial == "DOES_NOT_APPEAR": return "B wins!" # If A appears first, A wins ... vice versa elif rowsUntilA_initial < rowsUntilB_initial: return "A wins!" elif rowsUntilB_initial < rowsUntilA_initial: return "B wins!" # What if they are the same? elif rowsUntilB_initial == rowsUntilB_initial: return "... what happens if they're the same?"  Based on a quick test this does return the expected output:  Using this function it should be possible to make/map a new column, or rather even iterate once through each row and create a new column (which is what map would be doing anyway). I understand the objective here is to minimize iteration, but without referencing each row individually in some capacity - I'm not sure there's a way to compute and display the winners. The logic here and in your sample code seems similar, but I would be interested to know if the differences affect runtime. I do not have access to your dataset so I'm unable to determine that myself, but figured it might be worthwhile anyway to try.