首页 > 解决方案 > 使用来自另一个多索引数据帧的 .loc 填充数据帧值的最快方法

问题描述

我有一个数据 框 df1

key1    key2   val
1       100     
2       500   
4       400 

我也有一个多索引数据 框 df2

       c
a  b     
1 100  a
2 200  b
3 300  j
4 400  e
5 500  t

我想val从多索引数据框 df2中填充我的 df1 列

我试过了:

for index,row in df1.iterrows():
    try:
        data = df2.loc([row['key1'],row['key2'])
        df1.loc[(df1.key1 == row['key1']) & (df1.key2 == row['key2']), 'val'] = data
    except:
        pass

最后,我的 df1 应该是这样的:

key1    key2   val
1       100     a
2       500   
4       400     e

但我主要担心的是 df2(多索引 df)的实际长度约为 60-7 万行。

df1 的长度几乎不会是 10 行。(我想重复这个过程,以 df1 包含其他数据)

那么这个 .loc 使用 for 循环是否有效?它是最快的吗?

还是使用 .apply 会更快?

我希望这个迭代是最快的。

以最快的方式运行它有什么线索吗?

标签: pythonpandas

解决方案


在 pandas 中最好避免loopss -iterrowsapply(引擎盖下的循环),更好的是矢量化解决方案。

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.然后先排序再join(排序中不使用时序):

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

推荐阅读