Concordance index calculation
You will not get dramatic speedups untill you can vectorize the operations, but here are some tips already

indexing before iterating

instead of 

for i, row in df.iterrows():
    if row['event'] == 1:


If you do 

for i, row in df[df['event'] == 1].rows():


you will iterate over less rows.

itertuples

generally, itertuples is faster than iterrows

comparable_rows

for comparable_rows you are only interested in the proba and the length, so you might as well make this into a Series, or even better, a numpy array.

The test (df['event'] == 0) doesn't change during the iteration, so you can define a df2 = df[df['event'] == 0] outside of the loop

n_correct_rows

instead of len(comparable_rows[comparable_rows['proba'] &lt; row['proba']]), you can use the fact that True == 1 do (comparable_rows['proba'] &lt; row.proba).sum()

result

def c_index3(y_pred, events, times):
    df = pd.DataFrame(data={'proba':y_pred, 'event':events, 'time':times})
    n_total_correct = 0
    n_total_comparable = 0
    df = df.sort_values(by=['time'])
    df2 = df.loc[df['event'] == 0]
    for row in df[df['event'] == 1].itertuples():
        comparable_rows = df2.loc[(df2['time'] &gt; row.time), 'proba'].values
        n_correct_rows = (comparable_rows &lt; row.proba).sum()
        n_total_correct += n_correct_rows
        n_total_comparable += len(comparable_rows)

    return n_total_correct / n_total_comparable if n_total_comparable else N


timings

data = ([0.1, 0.3, 0.67, 0.45, 0.56], [1.0,0.0,1.0,0.0,1.0], [3.1,4.5,6.7,5.2,3.4])
%timeit c_index1(*data)



5.17 ms ± 33.6 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)



%timeit c_index3(*data)



3.77 ms ± 160 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)