I have given the comparison of all three discussed above.
Using values
%timeit df['value'] = df['a'].values % df['c'].values
139 µs ± 1.91 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
Without values
%timeit df['value'] = df['a']%df['c']
216 µs ± 1.86 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
Apply function
%timeit df['Value'] = df.apply(lambda row: row['a']%row['c'], axis=1)
474 µs ± 5.07 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)