尝试合并具有多种条件的数据帧

2024-06-06 03:53:59 发布

您现在位置:Python中文网/ 问答频道 /正文

这是一个奇怪的例子:我有3个数据帧,“prov\u data”包含一个提供者id,并根据区域和类别进行计数(即,该提供者与这些区域和类别交互的次数)。你知道吗

prov_data = DataFrame({'aprov_id':[1122,3344,5566,7788],'prov_region_1':[0,0,4,0],'prov_region_2':[2,0,0,0],
                  'prov_region_3':[0,1,0,1],'prov_cat_1':[0,2,0,0],'prov_cat_2':[1,0,3,0],'prov_cat_3':[0,0,0,4],
                   'prov_cat_4':[0,3,0,0]})

enter image description here

“投标资料”,包含相同的投标资料。你知道吗

tender_data = DataFrame({'atender_id':['AA12','BB33','CC45'],
                     'ten_region_1':[0,0,1,],'ten_region_2':[0,1,0],
                  'ten_region_3':[1,1,0],'ten_cat_1':[1,0,0],
                     'ten_cat_2':[0,1,0],'ten_cat_3':[0,1,0],
                   'ten_cat_4':[0,0,1]})

enter image description here

最后一个“不匹配”DF包含了供应商和投标方之间禁止的匹配。你知道吗

no_match = DataFrame({ 'prov_id':[1122,3344,5566], 
            'tender_id':['AA12','BB33','CC45']})

enter image description here

我需要执行以下操作:创建一个新的df,如果prov\u data&tender\u data DataFrames的行(1)与一个或多个类别匹配(即同一类别为>;0),并且(2)与一个或多个地区匹配,并且(3)不在no\u匹配列表中,则该df将附加这些行。你知道吗

所以这会给我这个数据框:

df = DataFrame({'aprov_id':[1122,3344,7788],'prov_region_1':[0,0,0],'prov_region_2':[2,0,0],
                  'prov_region_3':[0,1,1],'prov_cat_1':[0,2,0],'prov_cat_2':[1,0,0],'prov_cat_3':[0,0,4],
                   'prov_cat_4':[0,3,0], 'atender_id':['BB33','AA12','BB33'],
                     'ten_region_1':[0,0,0],'ten_region_2':[1,0,1],
                  'ten_region_3':[1,1,1],'ten_cat_1':[0,1,0],
                     'ten_cat_2':[1,0,1],'ten_cat_3':[1,0,1],
                   'ten_cat_4':[0,0,0]})

Tags: 数据iddataframedfdata提供者类别region
2条回答

只使用“标准”pandas技术的简单解决方案。你知道吗

prov_data['tkey'] = 1
tender_data['tkey'] = 1
df1 = pd.merge(prov_data,tender_data,how='outer',on='tkey')
df1 = pd.merge(df1,no_match,how='outer',left_on = 'aprov_id', right_on = 'prov_id')
df1['dropData'] = df1.apply(lambda x: True if x['tender_id'] == x['atender_id'] else False, axis=1)
df1['dropData'] = df1.apply(lambda x: (x['dropData'] == True) or not(
                                     ((x['prov_cat_1'] > 0 and x['ten_cat_1'] > 0) or
                                      (x['prov_cat_2'] > 0 and x['ten_cat_2'] > 0) or
                                      (x['prov_cat_3'] > 0 and x['ten_cat_3'] > 0) or
                                      (x['prov_cat_4'] > 0 and x['ten_cat_4'] > 0)) and(
                                      (x['prov_region_1'] > 0 and x['ten_region_1'] > 0) or
                                      (x['prov_region_2'] > 0 and x['ten_region_2'] > 0) or
                                      (x['prov_region_3'] > 0 and x['ten_region_3'] > 0))),axis=1)
df1 = df1[~df1.dropData]
df1 = df1[[u'aprov_id', u'atender_id', u'prov_cat_1', u'prov_cat_2', u'prov_cat_3',
          u'prov_cat_4', u'prov_region_1', u'prov_region_2', u'prov_region_3',
          u'ten_cat_1', u'ten_cat_2', u'ten_cat_3', u'ten_cat_4', u'ten_region_1',
          u'ten_region_2', u'ten_region_3']].reset_index(drop=True)

print df1.equals(df)

首先,我们对这两个数据帧做一个完全的交叉积,并将其与no_match数据帧合并,然后添加一个布尔列来标记要删除的所有行。你知道吗

布尔列由两个布尔lambda函数指定,并带有所有必要的条件,然后我们只取该列为False的所有行。你知道吗

由于合并操作,此解决方案对资源不太友好,因此如果您的数据非常大,则可能会对您不利。你知道吗

代码

# the first columns of each dataframe are the ids
# i'm going to use them several times
tid = tender_data.values[:, 0]
pid = prov_data.values[:, 0]
# first columns [1, 2, 3, 4] are cat columns
# we could have used filter, but this is good
# for this example
pc = prov_data.values[:, 1:5]
tc = tender_data.values[:, 1:5]
# columns [5, 6, 7] are rgn columns
pr = prov_data.values[:, 5:]
tr = tender_data.values[:, 5:]

# I want to mave this an m x n array, where
# m = number of rows in prov df and n = rows in tender
nm = no_match.groupby(['prov_id', 'tender_id']).size().unstack()
nm = nm.reindex_axis(tid, 1).reindex_axis(pid, 0)
nm = ~nm.fillna(0).astype(bool).values * 1

# the dot products of the cat arrays gets a handy
# array where there are > 1 co-positive values
# this combined with the a no_match construct
a = pd.DataFrame(pc.dot(tc.T) * pr.dot(tr.T) * nm > 0, pid, tid)
a = a.mask(~a).stack().index

fp = a.get_level_values(0)
ft = a.get_level_values(1)

pd.concat([
        prov_data.set_index('aprov_id').loc[fp].reset_index(),
        tender_data.set_index('atender_id').loc[ft].reset_index()
    ], axis=1)


   index  prov_cat_1  prov_cat_2  prov_cat_3  prov_cat_4  prov_region_1  \
0   1122           0           1           0           0              0   
1   3344           2           0           0           3              0   
2   7788           0           0           4           0              0   

   prov_region_2  prov_region_3 atender_id  ten_cat_1  ten_cat_2  ten_cat_3  \
0              2              0       BB33          0          1          1   
1              0              1       AA12          1          0          0   
2              0              1       BB33          0          1          1   

   ten_cat_4  ten_region_1  ten_region_2  ten_region_3  
0          0             0             1             1  
1          0             0             0             1  
2          0             0             1             1  

解释

  • 使用点积来确定匹配
  • 还有很多事情我以后会解释的

相关问题 更多 >