Q:

Add call sequence number as new column to large pandas DataFrame by unique row id

Background
I'm not really sure how to describe the problem I'm having but I am mostly looking for help in optimizing.  I have a very large dataset (100M+ records) that I need to add a column to the DataFrame with the number of attempts to the unique row (by row in the example).  
Each row can have multiple "calls".  Each call creates a new call id in the call column.  Imagine that every time you call a function it creates a new "attempt" and logs the timestamp.  I need to know, in order of timestamp, the call number to the given row as each row can have multiple calls. 
Data
Example data with 10 uniqe row index (input.csv):
row,call,timestamp
3,14,2020-03-12 15:29:08.337966+00:00
3,4,2020-03-12 22:23:50.398009+00:00
3,22,2020-03-13 19:10:08.289580+00:00
6,18,2020-03-25 15:32:24.221671+00:00
6,8,2020-03-25 18:34:15.283520+00:00
1,2,2020-04-21 17:23:32.851851+00:00
2,21,2020-04-21 19:30:40.451850+00:00
4,12,2020-04-21 22:43:24.331857+00:00
2,10,2020-04-22 20:36:55.811849+00:00
4,3,2020-04-22 22:42:07.500080+00:00
1,19,2020-04-23 21:47:03.231868+00:00
7,13,2020-05-08 16:25:11.423903+00:00
7,7,2020-05-08 19:42:57.733961+00:00
8,17,2020-05-18 19:50:41.623906+00:00
8,0,2020-05-20 20:50:07.843900+00:00
9,16,2020-05-26 14:44:27.423901+00:00
9,20,2020-05-27 19:21:55.263903+00:00
5,5,2020-06-08 14:14:30.436444+00:00
0,9,2020-06-08 17:06:50.716447+00:00
5,6,2020-06-08 20:10:00.136453+00:00
5,11,2020-06-08 20:11:05.856443+00:00
5,15,2020-06-09 17:44:57.336454+00:00
0,1,2020-06-09 20:42:43.234904+00:00

The desired output would be something like this (output.csv):
row,call,timestamp,call_index
3,14,2020-03-12 15:29:08.337966+00:00,0
3,4,2020-03-12 22:23:50.398009+00:00,1
3,22,2020-03-13 19:10:08.289580+00:00,2
6,18,2020-03-25 15:32:24.221671+00:00,0
6,8,2020-03-25 18:34:15.283520+00:00,1
1,2,2020-04-21 17:23:32.851851+00:00,0
2,21,2020-04-21 19:30:40.451850+00:00,0
4,12,2020-04-21 22:43:24.331857+00:00,0
2,10,2020-04-22 20:36:55.811849+00:00,1
4,3,2020-04-22 22:42:07.500080+00:00,1
1,19,2020-04-23 21:47:03.231868+00:00,1
7,13,2020-05-08 16:25:11.423903+00:00,0
7,7,2020-05-08 19:42:57.733961+00:00,1
8,17,2020-05-18 19:50:41.623906+00:00,0
8,0,2020-05-20 20:50:07.843900+00:00,1
9,16,2020-05-26 14:44:27.423901+00:00,0
9,20,2020-05-27 19:21:55.263903+00:00,1
5,5,2020-06-08 14:14:30.436444+00:00,0
0,9,2020-06-08 17:06:50.716447+00:00,0
5,6,2020-06-08 20:10:00.136453+00:00,1
5,11,2020-06-08 20:11:05.856443+00:00,2
5,15,2020-06-09 17:44:57.336454+00:00,3
0,1,2020-06-09 20:42:43.234904+00:00,1

Current Approach
import pandas as pd
df = pd.read_csv('input.csv')

# Sort all the data so we don't have to sort each subset later
df.sort_values('timestamp', inplace=True)

# If there is only one call (no dupes), the index will just be 0 by default
df['call_index'] = 0

# Find duplicated rows
dupes = df[df.duplicated(['row'], keep=False)].drop_duplicates(['row'], keep='last')

def update_call_index(row):
    # Find all calls to that row
    calls = df[df['row']==row].reset_index()
    for i, idx in enumerate(calls['index'].values):
        if i == 0:
            # This is set by the default above
            continue
        # Update the index for that call
        df.at[idx, 'call_index'] = i

dupes['row'].apply(update_call_index)
df.to_csv('output.csv', index=False)

The Question:
If I have millions of rows, is there a more efficient way to do this?  Is there a better way using a join or group by?

A:

First we fill the new call_index column with 1, then cumsum per row group and decrease this cumsum by 1 to make it start from 0 instead of 1:
df['call_index'] = 1
df.call_index = df.groupby('row').call_index.transform('cumsum') - 1

If you like you can even shorten it to a one-liner:
df['call_index'] = df.assign(call_index = 1).groupby('row').call_index.transform('cumsum') - 1

