python - 将列表与 DataFrame 中的每条记录进行比较

标签 python python-3.x pandas list

我有一个用例,我将同一列中的列表与其自身进行比较,代码如下:

for i in range(0,len(counts95)):
    for j in range(i+1,len(counts95)):
        for x in counts95['links'][i]:
            for y in counts95['links'][j]:
                if x == y and counts95['linkoflinks'][j] is None:
                    counts95['linkoflinks'][j] = counts95['index'][i]

该代码可以工作,但它对 Python 不友好(使用 4 个 for 循环),并且需要大量时间来执行该操作。 其背后的主要思想是链接 counts95['links'] 列表中的元素位于任何后续行中的记录,如果是,则更新列 linksoflinks :仅当 linksoflinks 列为 None(不覆盖)时才显示第一列的索引

找到下面的引用表:

counts95 = pd.DataFrame({'index': [616351, 616352, 616353,6457754], 
                   'level0': [25,30,35,100],
                   'links' : [[1,2,3,4,5],[23,45,2],[1,19,67],[14,15,16]],
                   'linksoflinks' : [None,None,None,None]})

编辑: 新数据框

counts95 = pd.DataFrame({'index': [616351, 616352, 616353,6457754,6566666,464664683], 
                   'level0': [25,30,35,100,200,556],
                   'links' : [[1,2,3,4,5],[23,45,2],[1,19,67],[14,15,16],[1,14],[14,1]],
                   'linksoflinks' : [None,None,None,None,None,None]})

期望的输出:

     index  level0            links  linksoflinks
0   616351      25  [1, 2, 3, 4, 5]         NaN
1   616352      30      [23, 45, 2]    616351.0
2   616353      35      [1, 19, 67]    616351.0
3  6457754     100     [14, 15, 16]         NaN
4  6566666     200           [1,14]    616351.0
5  6457754     556           [14,1]    616351.0

最佳答案

与示例数据帧构造函数相比,您所需的输出使用不同的值和列名称。我使用您想要的输出数据帧进行测试。

逻辑:
对于links的每个子列表,我们需要找到第一个重叠子列表的行索引(我的意思是数据帧的索引,而不是列index)。我们将使用这些行索引在 counts95 上按 .loc 进行切片,以获得列 index 的相应值。为了实现这一目标,我们需要执行以下几个步骤:

  • 将每个子列表与link 中的所有子列表进行比较。列表理解是 快速高效地完成这项任务。我们需要编写一个列表 理解创建 bool 二维掩码数组,其中每个子数组 包含重叠行的 True 值和非重叠行的 False 值(请查看此步骤 2D 掩模并检查链接列,您会看得更清楚)
  • 我们想要从顶部到当前子列表进行比较。 IE。常设 从当前行开始,我们只想向后比较到顶部。 因此,我们需要将任何前向比较设置为False。这是 np.tril
  • 的功能
  • 在此 2D 掩码的每个子数组内,True 的位置/索引为 当前子列表重叠的行的行索引。我们需要找到 这些位置为True。这是np.argmax的功能。 np.argmax 返回数组第一个最大元素的位置/索引。 True 被视为 1False 被视为 0。所以, 在任何具有 True 的子数组上,它会正确返回第一个重叠行索引。但是,在所有 False 子数组上,它返回 0。稍后我们将使用 where
  • 处理所有 False 子数组
  • np.argmax之后,2D-mask 被缩减为 1D-mask。的每个元素 该一维掩码是重叠子列表的行索引数。 将其传递给.loc以获取index列的相应值。 但是,结果也错误地包含了 row where 的子数组 2D-mask 包含所有False。我们希望这些行变成 NaN。这是 .where 的功能

方法一:
使用列表理解在每个 links 列表与 links 中的所有列表之间构造 bool 2D 掩码 m。我们只需要向后比较,因此使用np.tril将掩码的右上角三角形压缩为所有代表向前比较的False。最后,调用 np.argmax 获取 m 每行中第一个 True 的位置,并链接要转动的 where m 的所有 False 行变为 NaN

c95_list = counts95.links.tolist()
m = np.tril([[any(x in l2 for x in l1) for l2 in c95_list] for l1 in c95_list],-1)
counts95['linkoflist'] = (counts95.loc[np.argmax(m, axis=1), 'index']
                                  .where(m.any(1)).to_numpy())

 Out[351]:
     index  level0            links  linkoflist
0   616351      25  [1, 2, 3, 4, 5]         NaN
1   616352      30      [23, 45, 2]    616351.0
2   616353      35      [1, 19, 67]    616351.0
3  6457754     100     [14, 15, 16]         NaN
4  6566666     200          [1, 14]    616351.0
5  6457754     556          [14, 1]    616351.0
<小时/>

方法2:
如果数据帧很大,则将每个子列表仅与链接的顶部部分进行比较会使速度更快。在大数据帧上,方法 1 的速度可能是方法 1 的两倍。

c95_list = counts95.links.tolist()
m = [[any(x in l2 for x in l1) for l2 in c95_list[:i]] for i,l1 in enumerate(c95_list)]
counts95['linkoflist'] = counts95.reindex([np.argmax(y) if any(y) else np.nan 
                                                   for y in m])['index'].to_numpy()
<小时/>

分步说明(方法1)

m = np.tril([[any(x in l2 for x in l1) for l2 in c95_list] for l1 in c95_list],-1)

Out[353]:
array([[False, False, False, False, False, False],
       [ True, False, False, False, False, False],
       [ True, False, False, False, False, False],
       [False, False, False, False, False, False],
       [ True, False,  True,  True, False, False],
       [ True, False,  True,  True,  True, False]])

argmax 返回所有 False 行中第一个 True 和第一个 False 的位置。

In [354]: np.argmax(m, axis=1)
Out[354]: array([0, 0, 0, 0, 0, 0], dtype=int64)

使用argmax的结果进行切片

counts95.loc[np.argmax(m, axis=1), 'index']

Out[355]:
0    616351
0    616351
0    616351
0    616351
0    616351
0    616351
Name: index, dtype: int64

链接 where 将所有 False 对应的行从 m 转换为 NaN

counts95.loc[np.argmax(m, axis=1), 'index'].where(m.any(1))

Out[356]:
0         NaN
0    616351.0
0    616351.0
0         NaN
0    616351.0
0    616351.0
Name: index, dtype: float64

最后,输出的索引与 counts95 的索引不同,因此只需调用 to_numpy 即可获取 ndarray 分配给列 linkoflist counts95

关于python - 将列表与 DataFrame 中的每条记录进行比较,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60496917/

相关文章:

python - 双击时无法打开单个 tkinter 程序。我没有收到错误消息

python - 如何创建 Tkinter 主菜单

python - 如何退出所有已加入的进程以防任何一个进程出现异常 - Python

python - 更改 Altair 图中的图例编号范围

python - 将brewer2mpl发散颜色图与matplotlib结合使用,gamma 给出的结果很差,其值不同于 1

python - 在 pandas 和 matplotlib 中将 24 小时格式转换为 12 小时

python - 比较 pandas 中的日期时间的最快方法是什么?

python - 找出数据集中哪些特征共线

python - 通过 post 请求将二进制数据作为文件提交

python - 获取多索引中级别的最后一个元素