#python #csv #dask
#python #csv #dask
Вопрос:
Я использую DASK для чтения CSV-файла размером около 2 ГБ. Я хочу записать каждую строку в отдельные CSV-файлы с 255 номерами на основе некоторой хэш-функции, как показано ниже.
Мое наивное решение:
from dask import dataframe as dd
if __name__ == '__main__':
df = dd.read_csv('train.csv', header=None, dtype='str')
df = df.fillna()
for _, line in df.iterrows():
number = hash(line[2]) % 256
with open("{}.csv".format(number), 'a ') as f:
f.write(', '.join(line))
Этот способ занимает около 15 минут. Есть ли какой-либо способ, которым мы можем сделать это быстрее.
Комментарии:
1. Поскольку вы не делаете ничего необычного с вашим CSV, почему бы просто не использовать встроенный
csv
модуль? Кроме того, вы должны кэшировать свои обработчики файлов, чтобы не открывать и закрывать файлы в каждой строке вашего CSV-файла — в вашем случае нормально сохранить 256 дескрипторов открытых файлов и закрыть их в конце.2. Спасибо @zwer итак, должен ли я открывать все файлы раньше и пытаться перебирать данные?
3. Вы можете открывать их по запросу… Создайте словарь для хранения вашей карты, скажем,
file_map
, затем просто сделайте что-то вродеf = file_map.get(number)
иif f is None: f = file_map[number] = open('{}.csv'.format(number), 'a ')
вместо вашейwith ...
строки. Затем просто просмотрите их все и закройте дескрипторы, как только вы выполните итерацию по всей длине вашего CSV.4. Хорошо, прямо сейчас пытаюсь с помощью csv Reader и записываю только в один файл, но это все еще занимает больше времени.
5. По вашему мнению, какое идеальное время для такого рода задач?
Ответ №1:
Поскольку в вашей процедуре преобладает IO, маловероятно, что Dask в этом случае сделает что-либо, кроме добавления накладных расходов, если ваша хэш-функция действительно очень медленная. Я предполагаю, что это не так.
решение @zwer будет выглядеть примерно так
files = [open("{}.csv".format(number), 'a ') for number in range(255)]
for _, line in df.iterrows():
number = hash(line[2]) % 256
files[number].write(', '.join(line))
[f.close() for f in files]
Однако ваши данные, похоже, умещаются в памяти, поэтому вы можете найти гораздо лучшую производительность
for (number, group) in df.groupby(df.iloc[:, 2].map(hash)):
group.to_csv("{}.csv".format(number))
потому что вы записываете в каждый файл непрерывно, а не переходите между ними. В зависимости от вашего устройства ввода-вывода и буферизации разница может быть нулевой или огромной.
Комментарии:
1. Спасибо mdurant, я бы обязательно попробовал это.