对具有两个不断变化的 ID 的唯一用户进行分组

如何解决对具有两个不断变化的 ID 的唯一用户进行分组

你能想出一个更快的算法来解决这个问题吗?或者改进代码?

问题:

我有两个客户 ID:

  • ID1(例如电话号码)
  • ID2(例如电子邮件地址)

用户有时会更改其 ID1,有时会更改 ID2。怎么能 我找到了唯一身份用户?

示例:

ID1 = [7,7,8,9]

ID2 = [a,b,c]

预期结果:

ID3 = [Anna,Anna,Paul]

enter image description here

现实世界的场景大约有。每个列表 600 000 个项目。

这里已经有了一个 SQL 的想法:How can I match Employee IDs from 2 columns and group them into an array?

我从一个对 TypeScript 有这个想法的朋友那里得到了帮助:https://stackblitz.com/edit/typescript-leet-rewkmh?file=index.ts

我的第二个朋友帮我写了一些伪代码,我能够创建这个:

迄今为止最快(不再工作)的代码:

ID1 = [7,9]
ID2 = ["a","b","c"]

def timeit_function(ID1,ID2):
    
    def find_user_addresses():
        phone_i = []
        email_i = []
        
        tmp1 = [ID1[0]]
        tmp2 = []
        tmp_index = []

        while len(tmp1) != 0 or len(tmp2) != 0:
            while len(tmp1) != 0:
                tmp_index = []  
                for index,value in enumerate(ID1):
                    if value == tmp1[0]:
                        tmp2.append(ID2[index])
                        tmp_index.insert(-1,index)

                for i in tmp_index: 
                    del ID1[i]
                    del ID2[i]
                tmp1 = list(dict.fromkeys(tmp1))
                phone_i.append(tmp1.pop(0))

            while len(tmp2) != 0:
                tmp_index = [] 
                for index,value in enumerate(ID2):
                    if value == tmp2[0]:
                        tmp1.append(ID1[index])
                        tmp_index.insert(0,index)

                for i in tmp_index: 
                    del ID1[i]
                    del ID2[i]
                tmp2 = list(dict.fromkeys(tmp2))
                email_i.append(tmp2.pop(0))

        return phone_i,email_i
    
    users = {}
    i = 0
    while len(ID1) != 0:
        phone_i,email_i = find_user_addresses()
        users[i] = [phone_i,email_i]
        i += 1
    return users

输出:

{0: [[7,8],['a','b']],1: [[9],['c']]}

含义:{User_0: [[phone1,phone2],[email1,email2]],User_1: [phone3,email3]}

排名

排名 用户名 %timeit 唯一身份用户 正确的输出?
1. 扎卡里·万斯 每个循环 32 ms ± 1.9 ms(平均值 ± 标准偏差,7 次运行,每次 10 次循环) 1408 是的
2. 伊格里尼斯 每个循环 5.54 秒 ± 81.7 毫秒(平均值 ± 标准偏差。7 次运行,每个循环 1 个) 1408 是的
(3.) dkapitan 每个循环 8 秒 ± 106 毫秒(平均值 ± 标准偏差。7 次运行,每个循环 1 个) 3606 没有
(4.) thenarfer 每个循环 2.34 µs ± 3.25 µs(平均值 ± 标准偏差,7 次运行,每个循环 1 个) 1494 没有

代码使用两个列表 here 运行(加载需要一些时间)。

解决方法

这个想法很简单:

  • 对于每个条目
    • 扫描所有现有用户,

      • 如果条目的任何维度与之前的用户匹配,则扩展其属性集,并将其添加到合并列表中
    • 如果与现有的任何人都不匹配,则创建一个新用户,

    • 否则将不同的用户分组

这应该很快,因为它只扫描列表一次并且不需要递归。

ID1 = [7,7,8,9]
ID2 = ["a","b","c"]
user = {}
new_user_idx = 0
for i in range(len(ID1)):
    merge = []   # this is a list of users that should be merged
    for k in user:
        # find if any feature is already found in previous user  
        if ID1[i] in user[k][0]:
            user[k][1].add(ID2[i])
            merge.append(k)
        if ID2[i] in user[k][1]:
            user[k][0].add(ID1[i])
            merge.append(k)
    if not merge:
        # we have to create a new user
        user[new_user_idx] = (set([ID1[i]]),set([ID2[i]]))
        new_user_idx += 1
    elif len(merge)>1:
        # merging existing users
        for el in set(merge[1:]):
            if el==merge[0]: continue  # skip unnecessary merge
            user[merge[0]][0].update(user[el][0]) # copy attributes
            user[merge[0]][1].update(user[el][1])
            user.pop(el) # delete merged user
print(user)   


{0: ({7,8},{'a','b'}),1: ({9},{'c'})}
 
,

用套装试试:

%%timeit
ID1 = [7,"c"]

users = {0: {'phone': set([ID1[0]]),'email': set([ID2[0]])}}

for index,id1 in enumerate(ID1):
    id2 = ID2[index]
    
    # iterate over found list of users
    i = 0
    n_users = max(users.keys()) 
    while i <= n_users:
        if any([(id1 in users[i]['phone']),(id2 in users[i]['email'])]):
            users[i]['phone'].add(id1)
            users[i]['email'].add(id2)
            break
        i += 1

    # add new user if not found
    if i > n_users:
        users[i] = {'phone': set([id1]),'email': set([id2])}
,

不要使用包含 5 个元素的列表运行 timeit。这不是评估竞争者的有效方法。使用更大的列表(1000+)来测试性能,否则你实际上不会得到你想要的快速程序。

我会毫不犹豫地使用 O(N) 最坏情况算法(不依赖于用户数量)。

我会指出其他算法的性能在很大程度上取决于典型用户拥有的 ID 数量。这个专门用于为每个用户提供大量 ID。

ID1 = [7,"c"]

from collections import defaultdict

id1_to_id2 = defaultdict(set)
id2_to_id1 = defaultdict(set)
for id1,id2 in zip(ID1,ID2):
    id1_to_id2[id1].add(id2)
    id2_to_id1[id2].add(id1)

id1_to_user = {}
users = {}
for id1 in id1_to_id2:
    if id1 in id1_to_user:
        continue # Already processed

    # Find all id1 and id2 for this user,using 'floodfill'
    id1s = {id1}
    id2s = set()
    id1_queue = [id1]
    while len(id1_queue) > 0:
        old_id2s = id2s.copy()
        for id1 in id1_queue:
            id2s.update(id1_to_id2[id1]) # try using id2_queue = set().union(id1_to_id2[id1] for id1 in id1_queue)-id2s; id2s |= id2_queue as well in case it's faster
        id2_queue = id2s - old_id2s
        id1_queue = []
        old_id1s = id1s.copy()
        for id2 in id2_queue:
            id1s.update(id2_to_id1[id2])
        id2_queue = []
        id1_queue = id1s - old_id1s
    user = len(users)
    users[user] = [id1s,id2s]
    for id1 in id1s:
        id1_to_user[id1] = user

print(users)

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-
参考1 参考2 解决方案 # 点击安装源 协议选择 http:// 路径填写 mirrors.aliyun.com/centos/8.3.2011/BaseOS/x86_64/os URL类型 软件库URL 其他路径 # 版本 7 mirrors.aliyun.com/centos/7/os/x86
报错1 [root@slave1 data_mocker]# kafka-console-consumer.sh --bootstrap-server slave1:9092 --topic topic_db [2023-12-19 18:31:12,770] WARN [Consumer clie
错误1 # 重写数据 hive (edu)&gt; insert overwrite table dwd_trade_cart_add_inc &gt; select data.id, &gt; data.user_id, &gt; data.course_id, &gt; date_format(
错误1 hive (edu)&gt; insert into huanhuan values(1,&#39;haoge&#39;); Query ID = root_20240110071417_fe1517ad-3607-41f4-bdcf-d00b98ac443e Total jobs = 1
报错1:执行到如下就不执行了,没有显示Successfully registered new MBean. [root@slave1 bin]# /usr/local/software/flume-1.9.0/bin/flume-ng agent -n a1 -c /usr/local/softwa
虚拟及没有启动任何服务器查看jps会显示jps,如果没有显示任何东西 [root@slave2 ~]# jps 9647 Jps 解决方案 # 进入/tmp查看 [root@slave1 dfs]# cd /tmp [root@slave1 tmp]# ll 总用量 48 drwxr-xr-x. 2
报错1 hive&gt; show databases; OK Failed with exception java.io.IOException:java.lang.RuntimeException: Error in configuring object Time taken: 0.474 se
报错1 [root@localhost ~]# vim -bash: vim: 未找到命令 安装vim yum -y install vim* # 查看是否安装成功 [root@hadoop01 hadoop]# rpm -qa |grep vim vim-X11-7.4.629-8.el7_9.x
修改hadoop配置 vi /usr/local/software/hadoop-2.9.2/etc/hadoop/yarn-site.xml # 添加如下 &lt;configuration&gt; &lt;property&gt; &lt;name&gt;yarn.nodemanager.res