【问题标题】:Sorting a big file using its chunks使用其块对大文件进行排序
【发布时间】:2023-04-08 21:49:02
【问题描述】:

假设我们要对一个在column=X 周围有 40000 行的文件进行排序。让我们还假设相同的值在整个表中广泛存在,因此column=X 中具有相同值的行不仅在前 1000 行中被发现。现在,如果我们逐块读取文件并只考虑 1000 行,如果我们要围绕该列再次对表进行排序,我们可能会弄乱在 column=X 中找到的具有相同值的其他行。那么我们如何解决这个问题呢?由于没有可用数据,因此不需要代码,但我正在寻找您对此事的意见?我们是否应该通过将每个块并行地分配给合并排序算法然后重新组合结果来使用合并排序?我没有看到有办法用 pandas 做到这一点,但我不确定?

import pandas as pd
chunk_size = 1000
batch_no = 1
for chunk in pd.read_csv('data.csv', chunksize=chunk_size):
    chunk.sort_values(by='X', inplace=True)
    chunk.to_csv('data' +str(batch_no) + '.csv', index=False)
    batch_no +=1

【问题讨论】:

  • 貌似pandas的内置函数sort_values默认使用quicksort,但是你可以指定一个参数来使用mergesort - pandas.pydata.org/pandas-docs/version/0.23.0/generated/…
  • @tidakdiinginkan。谢谢。即使可以使用合并排序,使用块方法并围绕 column=X 对每个块进行排序,我不确定是否有可能在 column=X 中具有相同值的所有行,除非我们在不分块的情况下对表进行排序,或者如果我们对行进行分组将不同块中的相同值放在一起,即我们将来自不同块的coulmn=X中具有相同值的所有行分组在一起。

标签: python pandas chunks


【解决方案1】:

您需要merge 排序后的 csv 文件,幸运的是 Python 为它提供了一个函数。如下使用:

from operator import itemgetter

import pandas as pd
import numpy as np
import csv
import heapq

# generate test data
test_data = pd.DataFrame(data=[[f"label{i}", val] for i, val in enumerate(np.random.uniform(size=40000))],
                         columns=["label", "X"])
test_data.to_csv("data.csv", index=False)

# read and sort each chunk
chunk_size = 1000
file_names = []
for batch_no, chunk in enumerate(pd.read_csv("data.csv", chunksize=chunk_size), 1):
    chunk.sort_values(by="X", inplace=True)
    file_name = f"data_{batch_no}.csv"
    chunk.to_csv(file_name, index=False)
    file_names.append(file_name)

# merge the chunks
chunks = [csv.DictReader(open(file_name)) for file_name in file_names]
with open("data_sorted.csv", "w") as outfile:
    field_names = ["label", "X"]
    writer = csv.DictWriter(outfile, fieldnames=field_names)
    writer.writeheader()
    for row in heapq.merge(*chunks, key=itemgetter("X")):
        writer.writerow(row)

来自heapq.merge上的文档:

将多个排序后的输入合并到一个排序后的输出中(例如, 合并来自多个日志文件的带时间戳的条目)。返回一个 对排序值进行迭代。

类似于 sorted(itertools.chain(*iterables)) 但返回一个 可迭代,不会一次将数据全部拉入内存,并假设 每个输入流已经排序(最小到 最大)。

因此,使用 heapq.merge 将不会将所有数据加载到内存中,正如您在上面的引用(强调我的)中所读到的那样。还值得注意的是,这个函数的复杂度是O(n),其中n是整个数据的大小。因此整体排序算法为O(nlogn)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-05-15
    • 2020-09-08
    • 1970-01-01
    • 2011-11-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多