Существуют различные методы
Упорядочение набора данных (экономит время в будущем, но требует первоначальных затрат времени)
Разделение на части позволяет упростить многие операции, такие как тасование и т. Д.
Убедитесь, что каждый поднабор / блок является представительным для всего набора данных. Каждый файл чанка должен иметь одинаковое количество строк.
Это можно сделать, добавив строку в один файл за другим. Быстро, вы поймете, что неэффективно открывать каждый файл и писать строки. Особенно при чтении и записи на одном диске.
-> добавить буфер записи и чтения, который помещается в память.
Выберите размер, соответствующий вашим потребностям. Я выбрал именно этот размер, потому что мой текстовый редактор по умолчанию все еще может открывать его довольно быстро.
Меньшие куски могут повысить производительность, особенно если вы хотите получить метрики, такие как распределение классов, потому что вам нужно только l oop через один репрезентативный файл, чтобы получить оценку всего набора данных, которого может быть достаточно.
Большие фрагменты имеют лучшее представление всего набора данных в каждом файле, но вы также можете просто go через x меньшие фрагменты.
Я использую c# для этого, потому что у меня там больше опыта, и поэтому я могу использовать полный набор функций, таких как разбиение задач reading / processing / writing
на разные потоки.
Если у вас есть опыт использования python или r, я подозреваю, что должны быть аналогичные функции. Распараллеливание может быть огромным фактором для таких больших наборов данных.
Наборы фрагментированных данных могут быть смоделированы в один набор данных с чередованием, который можно обрабатывать с помощью тензорных единиц обработки. Это, вероятно, даст один из лучших показателей и может быть выполнен локально, а также в облаке на действительно больших машинах. Но для этого нужно много узнать о тензорном потоке.
Использование ридера и пошаговое чтение файла
вместо того, чтобы делать что-то вроде all_of_it = file.read()
, вы хотите использовать какой-нибудь потоковый ридер. Следующая функция читает построчно один из файлов фрагментов (или весь ваш набор данных объемом 300 ГБ), чтобы подсчитать каждый класс в файле. Обрабатывая по одной строке за раз, ваша программа не будет переполнять память.
Возможно, вы захотите добавить некоторые индикаторы прогресса, такие как X строк / с или X MBbs, чтобы оценить общее время процесса. .
def getClassDistribution(path):
classes = dict()
# open sample file and count classes
with open(path, "r",encoding="utf-8",errors='ignore') as f:
line = f.readline()
while line:
if line != '':
labelstring = line[-2:-1]
if labelstring == ',':
labelstring = line[-1:]
label = int(labelstring)
if label in classes:
classes[label] += 1
else:
classes[label] = 1
line = f.readline()
return classes
Я использую комбинацию наборов данных и оценки.
Подводные камни для производительности
- всякий раз, когда это возможно, избегайте вложенных циклов. Каждый l oop внутри другого l oop умножает сложность на n
- , когда это возможно, обрабатывает данные за один go. Каждое l oop за другим добавляет сложность n
- , если ваши данные поступают в формате csv, избегайте готовых функций, таких как
cells = int(line.Split(',')[8])
, это очень быстро приведет к узкому месту в пропускной способности памяти. Один правильный пример этого можно найти в getClassDistribution
, где я хочу получить только метку.
следующая C# функция разбивает строку csv на элементы очень быстро.
// Call function
ThreadPool.QueueUserWorkItem((c) => AnalyzeLine("05.02.2020,12.20,10.13").Wait());
// Parralelize this on multiple cores/threads for ultimate performance
private async Task AnalyzeLine(string line)
{
PriceElement elementToAdd = new PriceElement();
int counter = 0;
string temp = "";
foreach (char c in line)
{
if (c == ',')
{
switch (counter)
{
case 0:
elementToAdd.spotTime = DateTime.Parse(temp, CultureInfo.InvariantCulture);
break;
case 1:
elementToAdd.buyPrice = decimal.Parse(temp);
break;
case 2:
elementToAdd.sellPrice = decimal.Parse(temp);
break;
}
temp = "";
counter++;
}
else temp += c;
}
// compare the price element to conditions on another thread
Observate(elementToAdd);
}
Создайте базу данных и загрузите данные
при обработке данных в формате csv вы можете загрузить данные в базу данных.
Базы данных созданы для размещения большого количества данных, и вы можете ожидать очень высоких производительность.
База данных, скорее всего, займет больше места на диске, чем необработанные данные. Это одна из причин, почему я отказался от использования базы данных.
Оптимизация оборудования
Если ваш код хорошо оптимизирован, узким местом, скорее всего, будет пропускная способность жесткого диска.
- Если данные помещаются на локальный жесткий диск, используйте их локально, так как это избавит от задержек в сети (представьте 2-5 мс для каждой записи в локальной сети и 10-100 мс в удаленных местах) .
- Используйте современный жесткий диск. Сегодня твердотельный накопитель NVME емкостью 1 ТБ стоит около 130 (Intel 600p 1 ТБ). Nsme ssd использует p cie и примерно в 5 раз быстрее, чем обычный ssd, и в 50 раз быстрее, чем обычный жесткий диск, особенно при быстрой записи в разные места (разбивка данных). В последние годы твердотельные накопители значительно расширились, и для такой задачи это было бы дикостью.
На следующем снимке экрана приведено сравнение производительности тренировки тензорного потока с теми же данными на той же машине. Только один раз сохраненный локально на стандартном ssd и один раз на сетевом хранилище в локальной сети (обычный жесткий диск).