Just adding a visualization approach to what was said.
Profile and total total time df.apply : 
We see that the cumulative time is 13.8s .
Profile and total np.where total time: 
Here the cumulative time is 5.44ms , which is 2500 times faster than df.apply
The figure above was obtained using the snakeviz library. Here is a link to the library.
SnakeViz displays profiles as sunbeams, whose functions are represented as arcs. The root function is the circle in the middle, with the functions that it calls, the functions that will call these functions, and so on. The amount of time spent inside the function is represented by the width of the angular arc. An arc that flows around most of the circle is a function that takes up most of the time of its calling function, while a lean arc is a function that uses almost no time.
source share