使用Python创建一个非常大的二进制频率矩阵来运行协作过滤

2024-06-18 15:16:15 发布

您现在位置:Python中文网/ 问答频道 /正文

我尝试在一个大的医疗代码数据集上运行协作过滤,其中每个患者有2个或更多的诊断。有约291K名患者,有约8K个唯一代码。为了对这些数据运行CF,我需要创建一个二进制频率矩阵,其中每个唯一的代码都是一列,如果疾病是否存在,每个患者的行和列中都有一个0或1。你知道吗

问题是这个数据集有23亿个单元,而我的笔记本电脑有16gb的内存,无法处理它。我用重塑软件包在R中试过,结果崩溃了。我用Python(见下文)编写了代码,如果我将数据分为500名患者,大约需要24小时来处理。有人有更好的方法吗?我想知道循环结构中的循环是否效率太低?或者我应该用R中的sparseMatrix来处理这个数据吗?你知道吗

列出示例:

subset_patients =
[['1510395', 'R31', 'N359', 'I639', 'C440', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA'], ['1275226', 'T810', 'N813', 'N393', 'M8417', 'M679', 'M1997', 'L600', 'K529', 'R634', 'R15', 'N811', 'K573', 'K571', 'K222', 'D120', 'A099', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA'], ...... ]

sorted_codes = ['A009', 'A010', 'A011', 'A014', 'A020', 'A021', 'A022', 'A028', 'A029', ... ]

我的代码:

bin_freq_matrix = pd.DataFrame(0, index = np.arange(len(subset_patients)), columns = sorted_codes)

count = -1
for row in subset_patients:  #subset_patients is a small list of the patients
    for col in row:
        if col in sorted_codes:  #sorted_codes is the unique codes list
            count = count+1
            bin_freq_matrix.at[count, col]=1

print(bin_freq_matrix.head())

最新版本:

subset_patients = patients[0:1]

def marking(row):
    # here the traverse is in the natural order of columns
    hots = {col for col in row if col in sorted_codes_set}
    # here as well there are no jumps around the memory
    return [1 if col in hots else 0 for col in sorted_codes]

bin_freq_matrix = pd.DataFrame(subset_patients).apply(marking)

print(bin_freq_matrix)
for x in bin_freq_matrix[1]:
    if x==1:
        print("yes")

Tags: the数据代码in患者forbincol
1条回答
网友
1楼 · 发布于 2024-06-18 15:16:15

欢迎来到SO!实际上,您可以在这里使用一个稍微更优的解决方案。至少可以优化的东西很少。让我们一步一步地看看它们,朝着更全面地使用pandas功能的方向发展。你知道吗

  1. 优化循环体 有趣的是,您不需要对构建矩阵的实际代码进行太多更改。只需更改数据结构的定义,就可以使代码更加高效!以下代码行:

    如果列在排序的#代码中:#排序的#代码是唯一代码列表

与集合(对数特征)相比,由于列表的存在性测试具有线性big-O notation)特征,因此会对操作造成很大的性能损失,您可以通过更改用于检查值是否存在的sorted_codes副本的定义来轻松使用这些特性:

sorted_codes_set = set(sorted_codes)

除非使用binary search,否则对列表排序没有帮助。它与集合具有相同的特性,但您必须自己实现搜索。选择很简单:套路。你知道吗


  1. 从循环中删除不必要的操作。 循环中的代码将被重复数十亿次(在您的例子中),因此应该最大限度地优化它。你知道吗

下一行以随机顺序更改数据帧,这是个坏主意,因为pandas针对顺序访问进行了优化,否则会慢几个数量级:

bin_freq_matrix.at[count, col]=1

  1. 使用apply和函数而不是for循环。这可能带来最大的收益。你知道吗

最后一段代码:

def marking(row):
    # here the traverse is in the natural order of columns
    hots = {col for col in row if col in sorted_codes_set}
    # here as well there are no jumps around the memory
    return [1  if col in hots else 0 for col in sorted_codes]

bin_freq_matrix = pd.DataFrame(subset_patients).apply(marking)

相关问题 更多 >