В пандах лучше избегать loops
s - iterrows
и apply
(петли под капотом), лучше векторизованные решения.
Использовать join
с параметром on
:
#for improve performance sort index and columns
df2 = df2.sort_index()
df1 = df1.sort_values(['key1','key2'])
df = df1.join(df2, on=['key1','key2'])
print (df)
key1 key2 val c
0 1 100 NaN a
1 2 500 NaN NaN
2 4 400 NaN e
РЕДАКТИРОВАТЬ:
Другой подход - объединение MultiIndex
и столбцы значений и использование map
:
df2.index = ['{}_{}'.format(a,b) for a, b in df2.index]
print (df2)
c
1_100 a
2_200 b
3_300 j
4_400 e
5_500 t
df1['joined'] = df1['key1'].astype(str) + '_' + df1['key2'].astype(str)
print (df1)
key1 key2 val joined
0 1 100 NaN 1_100
1 2 500 NaN 2_500
2 4 400 NaN 4_400
df1['col'] = df1['joined'].map(df2['c'])
print (df1)
key1 key2 val joined col
0 1 100 NaN 1_100 a
1 2 500 NaN 2_500 NaN
2 4 400 NaN 4_400 e
Сроки :
np.random.seed(123)
N = 100000
df2 = pd.DataFrame(np.random.randint(10000, size=(N, 3)), columns=list('abc'))
df2 = df2.drop_duplicates(['a','b']).set_index(['a','b'])
print (df2.head())
c
a b
3582 1346 5218
7763 9785 7382
5857 96 6257
6782 4143 4169
5664 942 6368
df1 = df2.iloc[np.random.randint(N, size=10)].reset_index()
df1.columns = ['key1','key2','val']
print (df1)
key1 key2 val
0 5157 9207 283
1 6452 6474 7092
2 1264 5009 5123
3 86 7225 1025
4 7787 5134 637
5 9406 6119 8719
6 7479 1493 1525
7 4098 7248 7618
8 9921 7925 8547
9 2320 764 1564
1.Присоединиться с несортированными MultiIndex
, столбцы:
In [42]: %timeit df1.join(df2, on=['key1','key2'])
100 loops, best of 3: 11.1 ms per loop
2. Затем выполнить первую сортировку, а затем объединить (сортировка неиспользуется в таймингах):
df2 = df2.sort_index()
In [44]: %timeit df1.join(df2, on=['key1','key2'])
100 loops, best of 3: 10.5 ms per loop
3. map
решение, также присоединение MultiIndex
не учитывается в таймингах, если все те же данные выполняются только один раз:
df2.index = ['{}_{}'.format(a,b) for a, b in df2.index]
df1['joined'] = df1['key1'].astype(str) + '_' + df1['key2'].astype(str)
In [51]: %timeit df1['col'] = df1['joined'].map(df2['c'])
1000 loops, best of 3: 371 µs per loop
In [55]: %%timeit
...: df1['joined'] = df1['key1'].astype(str) + '_' + df1['key2'].astype(str)
...: df1['col'] = df1['joined'].map(df2['c'])
...:
1000 loops, best of 3: 1.08 ms per loop