0

我正在尝试计算大列表的子列表中项目的共现。换句话说,每对项目多久一起出现一次?本质上,我正在尝试替换以下代码:

from itertools import combinations, chain
from collections import Counter

list_of_lists = [[8, 3, 5, 7], [2, 4, 5, 6], [7, 3, 8, 1, 2, 9]]
t = chain.from_iterable(combinations(sorted(i), r=2) for i in list_of_lists)

print(Counter(t))
      
Counter({(3, 7): 2,
         (3, 8): 2,
         (7, 8): 2,
         (3, 5): 1,
         ...
         })

这段代码的问题是我在大数据集上的内存不足,所以我试图找到一个使用磁盘的数据库解决方案。目前,我正在将 SQLAlchemy 与 SQLite 数据库一起使用,它可以工作,但速度极慢(处理我当前使用的数据需要几天时间)。我想知道是否可以优化下面的代码,例如,通过批量执行插入或增量操作。

from itertools import combinations
from sqlalchemy import create_engine, Column, Integer, String
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base


Base = declarative_base()


class Edge(Base):
    __tablename__ = "edgelist"

    a = Column(String, primary_key=True)
    b = Column(String, primary_key=True)
    count = Column(Integer)

    def __repr__(self):
        return f"Edge {self.a} {self.b}"


engine = create_engine("sqlite:///edgelist.db")

Session = sessionmaker(bind=engine)
session = Session()

Base.metadata.create_all(engine)

list_of_lists = [[8, 3, 5, 7], [2, 4, 5, 6], [7, 3, 8, 1, 2, 9]]  # In my case, these much much bigger
for item_list in list_of_lists:
    for pair in combinations(item_list, 2):
        a, b = sorted(pair)
        q = session.query(Edge).filter_by(a=a, b=b)
        if q.first():
            q.update({Edge.count: Edge.count + 1})
        else:
            edge = Edge(a=a, b=b, count=1)
            session.add(edge)
    session.commit()

到目前为止,我已经尝试使用Session.merge(),但我似乎无法找到以这种方式增加值的方法。同样,Session.bulk_save_objects似乎不支持递增。我还查看了 PostgreSQL,它似乎通过 更好地支持 upsert on_conflict_do_update,尽管我没有任何改进这种方式的运气,老实说,我更喜欢更轻的 SQLite 解决方案。

对于解决方案,我最好的想法是在每次迭代中构造成对列表,然后批量插入/递增值。伪代码:

for item_list in list_of_lists:
    pairs = combinations(item_list, 2)
    bulk_list = [Edge(a=a, b=b, count=1) for a, b in pairs]
    session.bulk_save_objects(bulk_list)  # This, except increment if entry exists already
    session.commit()
4

0 回答 0