Unfortunately if working with strings in numpy/pandas always are loops under the hoods.
Idea is create DataFrame from split by whitespaces, forward filling last values, filter by isin and last test if all Trues per rows:
df1['IsPerson'] = (df1['Vendor'].str.split(expand=True)
.ffill(axis=1)
.isin(df2['Persons'].tolist())
.all(axis=1))
Solution with sets:
s = set(df2['Persons'])
df1['IsPerson'] = ~df1['Vendor'].map(lambda x: s.isdisjoint(x.split()))
Performance
Depends of length of Both DataFrames, number of unique values and number of matched values. So in real data should be different.
np.random.seed(123)
N = 100000
L = list('abcdefghijklmno ')
df1 = pd.DataFrame({'Vendor': [''.join(x) for x in np.random.choice(L, (N, 5))]})
df2 = pd.DataFrame({'Persons': [''.join(x) for x in np.random.choice(L, (N * 10, 5))]})
In [133]: %%timeit
...: s = set(df2['Persons'])
...: df1['IsPerson1'] = ~df1['Vendor'].map(lambda x: s.isdisjoint(x.split()))
...:
470 ms ± 7.02 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
In [134]: %%timeit
...: df1['IsPerson2'] = (df1['Vendor'].str.split(expand=True)
...: .ffill(axis=1)
...: .isin(df2['Persons'].tolist())
...: .all(axis=1))
...:
858 ms ± 18.5 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)