我在熊猫中有两张桌子:
df1:包含150K用户的用户ID和IP地址。
|---------------|---------------|
| User_ID | IP_Address |
|---------------|---------------|
| U1 | 732758368.8 |
| U2 | 350311387.9 |
| U3 | 2621473820 |
|---------------|---------------|
df2:包含其所属的IP地址范围和国家/地区,139K记录
|---------------|-----------------|------------------|
| Country | Lower_Bound_IP | Upper_Bound_IP |
|---------------|-----------------|------------------|
| Australia | 1023787008 | 1023791103 |
| USA | 3638734848 | 3638738943 |
| Australia | 3224798976 | 3224799231 |
| Poland | 1539721728 | 1539721983 |
|---------------|-----------------|------------------|
我的目标是在df1中创建一个国家/地区列,使得df1的IP_Address位于df2中该国家/地区的Lower_Bound_IP和Upper_Bound_IP范围之间。
|---------------|---------------|---------------|
| User_ID | IP_Address | Country |
|---------------|---------------|---------------|
| U1 | 732758368.8 | Indonesia |
| U2 | 350311387.9 | Australia |
| U3 | 2621473820 | Albania |
|---------------|---------------|---------------|
我的第一种方法是对两个表进行交叉连接(笛卡尔积),然后过滤到相关记录。但是,使用pandas.merge()的交叉连接是不可行的,因为它将创建210亿条记录。代码每次都崩溃了。你能否提出一个可行的替代解决方案?
答案 0 :(得分:0)
我不确定如何使用pandas.where来处理这个问题,但是使用numpy.where你可以做到
idx = numpy.where((df1.Ip_Address[:,None] >= df2.Lower_Bound_IP[None,:])
& (df1.IP_Address[:,None] <= df2.Upper_Bound_IP[None,:]))[1]
df1["Country"] = df2.Country[idx]
numpy.where给出给定条件为True的索引。 '&安培;'对应于'和',整个[:,None]位添加一个虚拟轴,其中'None'位于其中。这可以确保您为每个User_ID找到df2中的索引,其中IP_Address在该范围内。 '[1]'给出条件为真的df2中的索引。 如果df2中的范围重叠,这将会中断。
这可能仍会导致内存问题,但您可以添加一个循环,以便批量执行此比较。 E.g。
batch_size = 1000
n_batches = df1.shape[0] // batch_size
# Integer division rounds down, so if the number
# of User_ID's is not divisable by the batch_size,
# we need to add 1 to n_batches
if n_batches * batch_size < df1.shape[0]:
n_batches += 1
indices = []
for i in range(n_batches):
idx = numpy.where((df1.Ip_Address[i*batch_size:(i+1)*batch_size,None]
>= df2.Lower_Bound_IP[None,:]) &
(df1.IP_Address[i*batch_size:(i+1)*batch_size,None]
<= df2.Upper_Bound_IP[None,:]))[1]
indices.extend(idx.tolist())
df1["Country"] = df2.Country[np.asarray(indices)]