To test my solution, I used the following DataFrame with smaller number
of codes:
    0   1    2    3    4    5    6    7    8    9
0  fl  nc  NaN  NaN  NaN  NaN  NaN  NaN  NaN  NaN
1  fl  nc  NaN  NaN  NaN  NaN  NaN  NaN  NaN  NaN
2  ct  dc   fl   hi   il   ky   la   md   mi   ms
3  ct  dc   fl   il   ky   la   md   mi   ms   nc
4  hi  pr  NaN  NaN  NaN  NaN  NaN  NaN  NaN  NaN
5  hi  il   ky   md   mi   ms  NaN  NaN  NaN  NaN
6  hi  il   ky   la   mi   ms  NaN  NaN  NaN  NaN
7  ct  la   md   ms   nc  NaN  NaN  NaN  NaN  NaN
8  dc  md   mi   ms   nc  NaN  NaN  NaN  NaN  NaN
9  dc  md   mi   nc  NaN  NaN  NaN  NaN  NaN  NaN
To create Final_Df I started with a list of codes:
codes = ['ca', 'ct', 'dc', 'fl', 'hi', 'il', 'ky', 'la', 'md', 'mi', 'ms', 'nc', 'pr']
and created Final_Df (full of zeroes) the following way:
Final_Df = pd.DataFrame(0, index=df.index, columns=codes)
I need also a dictionary to translate codes into column numbers,
with -1 for NaN (these values will be omitted):
codeToInd = { code: ind for ind, code in enumerate(codes) }
codeToInd[np.nan] = -1
The first step of actual computation is to translate df into ind - a
Numpy array:
ind = np.vectorize(codeToInd.get)(df)
The result is:
array([[ 3, 11, -1, -1, -1, -1, -1, -1, -1, -1],
       [ 3, 11, -1, -1, -1, -1, -1, -1, -1, -1],
       [ 1,  2,  3,  4,  5,  6,  7,  8,  9, 10],
       [ 1,  2,  3,  5,  6,  7,  8,  9, 10, 11],
       [ 4, 12, -1, -1, -1, -1, -1, -1, -1, -1],
       [ 4,  5,  6,  8,  9, 10, -1, -1, -1, -1],
       [ 4,  5,  6,  7,  9, 10, -1, -1, -1, -1],
       [ 1,  7,  8, 10, 11, -1, -1, -1, -1, -1],
       [ 2,  8,  9, 10, 11, -1, -1, -1, -1, -1],
       [ 2,  8,  9, 11, -1, -1, -1, -1, -1, -1]])
One more preparatory step is to extract the underlaying Numpy array
from Final_Df:
finDfVal = Final_Df.values
And the actual processing (setting *1*s at proper cells) is performed
with the following loop:
for r, c in np.argwhere(ind >= 0):
    finDfVal[r, ind[r, c]] = 1
After that Final_Df contains:
   ca  ct  dc  fl  hi  il  ky  la  md  mi  ms  nc  pr
0   0   0   0   1   0   0   0   0   0   0   0   1   0
1   0   0   0   1   0   0   0   0   0   0   0   1   0
2   0   1   1   1   1   1   1   1   1   1   1   0   0
3   0   1   1   1   0   1   1   1   1   1   1   1   0
4   0   0   0   0   1   0   0   0   0   0   0   0   1
5   0   0   0   0   1   1   1   0   1   1   1   0   0
6   0   0   0   0   1   1   1   1   0   1   1   0   0
7   0   1   0   0   0   0   0   1   1   0   1   1   0
8   0   0   1   0   0   0   0   0   1   1   1   1   0
9   0   0   1   0   0   0   0   0   1   1   0   1   0
Execution speed
Using %timeit I compared the execution time of my code with yours
and on this very limited data sample I got about 7 times shorter time.
I think that on a bigger DataFrame the difference should be greater.
Write what was the execution time of your code and mine.
In case of an error
To check what is goin on, try to create a DataFrame counterpart of ind,
just for display:
df.applymap(lambda x: codeToInd[x])
If everything is OK, a DataFrame with translated codes should be printed.
But in case of any missing value in codeToInd a KeyError exception
is raised, showing the missing value.
Add this missing value to codes and repeat the whole procedure.