【问题标题】:Merge Dictionaries Based on Matching Values from 2 Specified Keys [Matching Values are in Numpy Arrays]基于来自 2 个指定键的匹配值合并字典 [匹配值在 Numpy 数组中]
【发布时间】:2022-01-26 07:50:46
【问题描述】:

环顾四周,但尚未找到解决此问题的方法。抱歉,如果我错过了。

我正在尝试使用值是 numpy 数组的字典创建相当于 pandas 合并或 SQL JOIN 的内容。

以下是示例输入/期望的目标是什么。

Ex 输入

import numpy as np
dict_1 = {
    'col1': np.array(['one', 'two', 'three', 'four']), 
    'col2': np.array(['item1', 'item2', 'item3','item4'])}
dict_2 = {
    'col3': np.array(['two', 'two', 'six', 'seven', 'eight']), 
    'col4': np.array(['item2', 'item3','item4','item5','item 5'])}

~Ex 期望的输出(更新):~

new_dict = {
    'col1': array(['one', 'two', 'two', 'two', 'three', 'four']),
    'col2': array(['item1', 'item2', 'item2','item3','item3','item4']),
    'col3': array([np.nan, 'two', 'two', np.nan, np.nan]),
    'col4': array([np.nan, 'item2', 'item3', np.nan, np.nan, np.nan]),
}  

所以这里的目标是该函数将识别dict_1 中的col1dict_2 中的col3 之间的匹配,然后返回所有优先级在左侧的匹配。

即,即使没有匹配项,左侧的优先级 == four 也会返回,因为它在 dict_1 中 - 类似于您在以下位置看到的:

  1. 在 2 个 DataFrames 上的 pandas 合并 how='left'
  2. 两个数据库表上的 sql 中的 LEFT JOIN

当然,我可以将字典转换为 DataFrames 并使用 pandas 合并,但最好不使用 pandas 来解决这个问题。

任何帮助将不胜感激!

谢谢

以下是如何使用 Pandas Merge 实现预期结果

import pandas as pd
import numpy as np

dict_1 = {
    'col1': np.array(['one', 'two', 'three', 'four']), 
    'col2': np.array(['item1', 'item2', 'item3','item4'])}
dict_2 = {
    'col3': np.array(['two', 'two', 'six', 'seven', 'eight']), 
    'col4': np.array(['item2', 'item3','item4','item5','item 5'])}

df1 = pd.DataFrame(dict_1)
df2 = pd.DataFrame(dict_2)

new_df = df1.merge(df2, how='left', left_on='col1', right_on='col3')
new_df

【问题讨论】:

  • 能否请您展示如何使用pandas.Dataframe.merge 从您的示例中获得所需的输出。
  • 啊,对不起。晚上太晚了,意识到我在预期的输出中犯了一个错误。现在将更新寻找类似 new_df = df1.merge(df2, how='left', left_on='col1', right_on='col3')
  • @Bob - 对此感到抱歉。更新了帖子以显示正确的输出 + 如何使用 pandas 合并完成同样的一般事情。
  • 你想要所有四列?您打算将它用于大型阵列还是仅用于小型阵列(例如
  • @Bob - 是的,我需要理想地返回所有列。数组将相当大(在一些最大的用例中,数组内的值超过 10k - 但通常每个数组会有 500 - 1000 个值)。

标签: python numpy


【解决方案1】:

最终弄清楚如何做到这一点(不是 1:1 匹配上述要求 - 但类似 / 得到相同的所需输出)。

绝对不是世界上最干净的解决方案(甚至没有接近),但它可以完成工作......

这是最终脚本:

import numpy as np
import sm_pandas as spd

struct_arr1 = np.array([('jason', '28', 'j@j.com', 'j@j.com'), ('jared', '31', 'jm@j.com', 'j@j.com'),('george', '28', 'gmm@j.com', 'j@j.com')],
           dtype=[('name', 'object'), ('ag', 'object'), ('emai', 'object'), ('email', 'object')])

struct_arr2 = np.array([('jason', '22', 'jm@j.com'), ('jason', '27', 'jmm@j.com'), ('jared', 22, 'm@j.com')],
           dtype=[('name', 'object'), ('age', 'object'), ('email', 'object')])

def removeDuplicates(lst):
      
    return [t for t in (set(tuple(i) for i in lst))]


def join_by_left(key, r1, r2):
    # figure out the dtype of the result array
    key1 = r1.dtype.descr
    list_keys1 = [d[0] for d in key1]
    
    key2 = r2.dtype.descr
    list_keys2 = [d[0] for d in key2]

    len_keys = len(list_keys1)

    # get a dict of the rows of r2 grouped by key
    rows2 = {}
    for row2 in r2:
        rows2.setdefault(row2[key], []).append(row2)

    # merge the data into the return array
    new_arr = []
    for row1 in r1:
        if row1[key] in rows2: # return matching on key
            for row2 in rows2[row1[key]]:
                ret = tuple(row1[list_keys1]) + tuple(row2[list_keys2])
                new_arr.append(ret)

        else: # for left join to return non-matches on left side
            for j in range(len_keys):
                null = ('na','na','na')
                ret = tuple(row1[list_keys1]) + tuple(null)
                new_arr.append(ret)

    new_arr = removeDuplicates(lst=new_arr) # remove any duplicates

    return new_arr

new_arr = join_by_left(key='name', r1=struct_arr1, r2=struct_arr2)

# convert to list of lists
final = []
r = len(new_arr[0])
for num in range(r):
    fields = [i[num] for i in new_arr]
    final.append(fields)

# convert list of lists to dict
new_dict = {}
i=1
for item in final:
    ndict = {f'field{i}': np.array(item)}
    new_dict.update(ndict)
    i = i + 1

print(new_dict)

返回

{
    'field1': array(['jared', 'jason', 'george', 'jason'], dtype='<U6'), 
    'field2': array(['31', '28', '28', '28'], dtype='<U2'), 
    'field3': array(['jm@j.com', 'j@j.com', 'gmm@j.com', 'j@j.com'], dtype='<U9'), 
    'field4': array(['j@j.com', 'j@j.com', 'j@j.com', 'j@j.com'], dtype='<U7'), 
    'field5': array(['jared', 'jason', 'na', 'jason'], dtype='<U5'), 
    'field6': array(['22', '27', 'na', '22'], dtype='<U11'), 
    'field7': array(['m@j.com', 'jmm@j.com', 'na', 'jm@j.com'], dtype='<U9')
}

【讨论】:

    猜你喜欢
    • 2019-07-13
    • 1970-01-01
    • 2021-10-20
    • 2021-01-10
    • 1970-01-01
    • 2017-09-15
    • 1970-01-01
    • 2021-06-24
    • 1970-01-01
    相关资源
    最近更新 更多