熊猫-具有2个数据帧的最快方式索引

时间:2018-07-22 21:38:12

标签: python-3.x pandas numpy dataframe optimization

我正在使用带有Pandas库的Python 3开发软件。

时间很重要,但记忆并不多。

为了获得更好的可视化效果,我使用了名称 a b ,尽管值更多,但使用的值很少:

a -> 50000行

b -> 5000行

我需要从数据框 a b 中选择(使用多个条件)

a = pd.DataFrame({
'a1': ['x', 'y', 'z'] ,
'a2': [1, 2, 3],
'a3': [3.14, 2.73, -23.00],
'a4': [pd.np.nan, pd.np.nan, pd.np.nan]
})

a
  a1  a2     a3  a4
0  x   1   3.14 NaN
1  y   2   2.73 NaN
2  z   3 -23.00 NaN

b = pd.DataFrame({
'b1': ['x', 'y', 'z', 'k', 'l'],
'b2': [2018, 2019, 2020, 2015, 2012] 
})

b
  b1    b2
0  x  2018
1  y  2019
2  z  2020
3  k  2015
4  l  2012

到目前为止,我的代码是这样的:

for index, row in a.iterrows():
    try:
        # create a key
        a1 = row["a1"]

        mask = b.loc[(b['b1'] == a1) & (b['b2'] != 2019)]

        # check if exists 
        if (len(mask.index) != 0): #not empty
            a.loc[[index], ['a4']] = mask.iloc[0]['b2']

    except KeyError: #not found
        pass

但是正如您所看到的,与其他方法相比,我正在使用进行迭代速度非常慢,并且我正在更改要迭代的DataFrame的值,不建议这样做。

您能帮我找到一个更好的方法吗?结果应该是这样的:

a
  a1  a2     a3  a4
0  x   1   3.14 2018
1  y   2   2.73 NaN
2  z   3 -23.00 2020

我在下面尝试了类似的方法,但是我没有使它起作用。

a.loc[ (a['a1'] == b['b1']) , 'a4'] = b.loc[b['b2'] != 2019] 

*实际代码有更多条件

谢谢!

编辑

我使用以下方法进行基准测试:索引合并 set_index / loc 。这是代码:

import timeit
import pandas as pd

def f_iterrows():
    for index, row in a.iterrows():
        try:
            # create a key
            a1 = row["a1"]
            a3 = row["a3"]

            mask = b.loc[(b['b1'] == a1) & (b['b2'] != 2019)]

            # check if exists
            if len(mask.index) != 0:  # not empty
                a.loc[[index], ['a4']] = mask.iloc[0]['b2']

        except:  # not found
            pass

def f_merge():
    a.merge(b[b.b2 != 2019], left_on='a1', right_on='b1', how='left').drop(['a4', 'b1'], 1).rename(columns={'b2': 'a4'})

def f_lock():
    df1 = a.set_index('a1')
    df2 = b.set_index('b1')
    df1.loc[:, 'a4'] = df2.b2[df2.b2 != 2019]

#variables for testing
number_rows = 100
number_iter = 100

a = pd.DataFrame({
    'a1': ['x', 'y', 'z'] * number_rows,
    'a2': [1, 2, 3] * number_rows,
    'a3': [3.14, 2.73, -23.00] * number_rows,
    'a4': [pd.np.nan, pd.np.nan, pd.np.nan] * number_rows
})

b = pd.DataFrame({
    'b1': ['x', 'y', 'z', 'k', 'l'] * number_rows,
    'b2': [2018, 2019, 2020, 2015, 2012] * number_rows
})

print('For: %s s' % str(timeit.timeit(f_iterrows, number=number_iter)))
print('Merge: %s s' % str(timeit.timeit(f_merge, number=number_iter)))
print('Loc: %s s' % str(timeit.timeit(f_iterrows, number=number_iter)))

它们全部都起作用:)并且运行时间为:

  

对于:277.9994369489998 s

     

位置:274.04929955067564 s

     

合并:2.195712725706926 s

到目前为止,合并是最快的。

如果出现其他选项,我会在这里更新,再次感谢。

2 个答案:

答案 0 :(得分:1)

IIUC

a.merge(b[b.b2!=2019],left_on='a1',right_on='b1',how='left').drop(['a4','b1'],1).rename(columns={'b2':'a4'})
Out[263]: 
  a1  a2     a3      a4
0  x   1   3.14  2018.0
1  y   2   2.73     NaN
2  z   3 -23.00  2020.0

答案 1 :(得分:0)

IIUC,

df1 = df1.set_index('a1')
df2 = df2.set_index('b1')

然后就

df1.loc[:, 'a4'] = df2.b2[df2.b2 != 2019]

    a1  a2  a3      a4
0   x   1   3.14    2018.0
1   y   2   2.73    NaN
2   z   3   -23.00  2020.0