python – 按复杂条件合并/加入2个DataFrame
我有2个大型数据集(每个70K到110K大).我想关联/比较两者,并根据某些条件/标准找到set1中的哪些项目可以在set1中找到.
我当前的策略是按公共字段对两个列表进行排序,然后运行嵌套for循环,执行条件if测试,聚合预定义的dict与找到的项目和不匹配的项目. 例: import pandas as pd list1 = [{'a': 56,'b': '38','c': '11','d': '10','e': 65},{'a': 31,'b': '12','c': '26','d': '99','e': 71},{'a': 70,'b': '49','c': '40','d': '227','e': 1},{'a': 3,'b': '85','c': '32','d': '46','e': 70},] list2 = [{'a': 56,{'a': 145,'b': '108','c': '123','d': '84','e': 3},{'a': 113,'b': '144','c': '183','d': '7','e': 12},{'a': 144,'b': '60','c': '46','d': '106','e': 148},{'a': 57,'b': '87','c': '51','d': '95','e': 187},{'a': 41,{'a': 80,{'a': 107,'b': '95','c': '81','d': '15','e': 25},{'a': 138,'b': '97','c': '38','d': '28','e': 171}] re_dict = dict([('found',[]),('alien',[])]) for L2 in list2: for L1 in list1: if (L1['a']-5 <= L2['a'] <= L2['a']+10) and L2['c'][-1:] in L1['c'][-1:]: if (65 <= L2['e'] <= 75): L2.update({'e': 'some value'}) re_dict['found'].append(L2) list1.remove(L1) break # break out from the inner loop else: # if the inner loop traversed entire list,there were no matches re_dict['alien'].append(L2) 以上产生了预期结果: re_dict {'alien': [{'a': 145,'e': 171}],'found': [{'a': 56,'e': 'some value'},'e': 'some value'}]} 所以它完成了这项工作,但显然效率不高,似乎是大熊猫的理想工作. 我认为如果我可以合并/加入两个DataFrame,那将是理想的,但我无法弄清楚如何合并复杂的标准.我的数据集大小也不相同. 例: df1 = pd.DataFrame(list1) df2 = pd.DataFrame(list2) pd.merge(df1,df2,on='d',how='outer') a_x b_x c_x d e_x a_y b_y c_y e_y 0 56 38 11 10 65 56 38 11 65 1 31 12 26 99 71 41 12 26 71 2 70 49 40 227 1 80 49 40 1 3 3 85 32 46 70 3 85 32 70 4 NaN NaN NaN 84 NaN 145 108 123 3 5 NaN NaN NaN 7 NaN 113 144 183 12 6 NaN NaN NaN 106 NaN 144 60 46 148 7 NaN NaN NaN 95 NaN 57 87 51 187 8 NaN NaN NaN 15 NaN 107 95 81 25 9 NaN NaN NaN 28 NaN 138 97 38 171 它仅在d d1和df2中d列完全相等时合并. 解决方法
pandas目前缺乏对“附近”查询的直接支持,尽管我有一个
pull request可以添加一些基本功能(对于你的用例来说还不够).
幸运的是,科学的Python生态系统为您提供了自己完成此操作所需的工具. 加入附近位置的有效方法是使用树数据结构,如scikit-learn documentation中所述.SciPy和scikit-learn都有合适的KDTree实现. 使用完全临时规则并不容易(或有效),但只要您有明确定义的距离度量,就可以有效地进行最近邻查找.我相信scikit-learn的KDTree甚至可以让你定义自己的距离度量,但我们会坚持正常的欧几里德距离继续你的例子: from scipy.spatial import cKDTree as KDTree import pandas as pd # for each row in df2,we want to join the nearest row in df1 # based on the column "d" join_cols = ['d'] tree = KDTree(df1[join_cols]) distance,indices = tree.query(df2[join_cols]) df1_near_2 = df1.take(indices).reset_index(drop=True) left = df1_near_2.rename(columns=lambda l: 'x_' + l) right = df2.rename(columns=lambda l: 'y_' + l) merged = pd.concat([left,right],axis=1) 这导致: x_a x_b x_c x_d x_e y_a y_b y_c y_d y_e 0 56 38 11 10 65 56 38 11 10 65 1 31 12 26 99 71 145 108 123 84 3 2 56 38 11 10 65 113 144 183 7 12 3 31 12 26 99 71 144 60 46 106 148 4 31 12 26 99 71 57 87 51 95 187 5 31 12 26 99 71 41 12 26 99 71 6 70 49 40 227 1 80 49 40 227 1 7 3 85 32 46 70 3 85 32 46 70 8 56 38 11 10 65 107 95 81 15 25 9 56 38 11 10 65 138 97 38 28 171 如果你想基于多列的接近度进行合并,就像设置join_cols = [‘d’,’e’,’f’]一样简单. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |