通过存储索引来提高熊猫过滤器的速度?

时间:2018-06-26 14:53:27

标签: python postgresql pandas dataframe

我有以下df:

let giftcardSlider = UIkit.slider('#giftcard-slider', { autoplay: false});

我这样累积AREA列:

df = pd.DataFrame({'ID1':[1,2,3,4,5,6],'ID2':[2,6,6,2,1,2],'AREA':[1,1,1,1,1,1]})
...

    ID1 ID2 AREA
0   1   2   1
1   2   6   1
2   3   6   1
3   4   2   1
4   5   1   1
5   6   2   1

对于for id_ in df.ID1: id1_filter = df.ID1 == id_ id2_filter = (df.ID1 == id_) | (df.ID2 == id_) df.loc[id1_filter, 'AREA'] = df.loc[id2_filter].AREA.sum() print(df) ... ID1 ID2 AREA 0 1 2 2 1 2 6 5 2 3 6 1 3 4 2 1 4 5 1 1 5 6 2 7 中的每个id_,将ID1求和,其中AREA == ID1id_, 并且它始终在ID2 == id_上对df进行排序时运行。

尽管我正在处理的实际数据帧是150,000条记录,每一行都属于一个唯一的ID1。 在此数据帧上运行上述操作需要2.5个小时。由于此操作将反复发生 在可预见的将来,我决定将True值的索引存储在ID1id1_filter中 在具有以下架构的数据库中。

表ID1:

id2_filter

表ID2:

ID_,INDEX_
1  ,   0
2  ,   1
etc, ect

下次我在ID_,INDEX_ 1 , 0 1 , 4 2 , 0 2 , 1 2 , 3 2 , 5 etc, etc 列上运行累积(现在已填充了不同的AREA值) 我读了sql表,并将其转换为字典。然后,我使用这些命令 在求和循环中获取我需要的记录。

AREA

以这种方式运行仅需6分钟!

我的问题:是否有更好/标准的方法来处理这种情况,即存储用于 以后使用?旁注,我在SQL表的ID列上设置了索引,并尝试获取 通过查询表中的每个ID进行索引,效果很好,但仍比上述时间长(9分钟)。

1 个答案:

答案 0 :(得分:1)

一种方法是这样的:

df = df.set_index('ID1') 
for row in df.join(df.groupby('ID2')['AREA'].apply(lambda x: x.index.tolist()),rsuffix='_').dropna().itertuples():
    df.loc[row[0],'AREA'] += df.loc[row[3],'AREA'].sum()
df = df.reset_index()

您将获得预期的结果

   ID1  ID2  AREA
0    1    2     2
1    2    6     5
2    3    6     1
3    4    2     1
4    5    1     1
5    6    2     7

现在使用更大的df,例如:

df = pd.DataFrame( {'ID1':range(1,1501),'ID2': np.random.randint(1,1501,(1500,)),'AREA':[1]*1500}, 
                   columns = ['ID1','ID2','AREA'])

当您的第一个方法运行6.5 s时,此处介绍的方法在我的计算机上的运行时间约为0.76 s。

最终,您可以创建一个df_list,例如:

df_list = (df.set_index('ID1')
             .join(df.set_index('ID1').groupby('ID2')['AREA']
                     .apply(lambda x: x.index.tolist()),rsuffix='_ID2')
             .dropna().drop(['AREA','ID2'],1))

将链接ID1和ID2的信息保留在某处:在这里您可以看到ID 2列中的ID等于2,其中ID1的值= 1、4和6

      AREA_ID2
ID1           
1          [5]
2    [1, 4, 6]
6       [2, 3]

,然后您可以运行以不重新创建df_list,但代码略有不同:

df = df.set_index('ID1') 
for row in df_list.itertuples():
    df.loc[row[0],'AREA'] += df.loc[row[1],'AREA'].sum()
df = df.reset_index()

希望它更快