@delkov

[Большой txt ~1 гб] как обработать?

Доброго времени суток.
Имеется большой txt ~ 1гб, вида:
x y z text text
...

Надо собрать все повторения пары x y и просуммировать их z.
Ex:

1 2 5 тест тест
1 2 10 тест тест

После обработки:
1 2 15 тест

Код на matlab (очень долго):
fid = fopen(strcat('test.txt'));
T = textscan(fid, '%f %f %f %*[^\n]');

A = T{1};
B = T{2}; 
C = T{3};

A_2 = [];
B_2 = [];
C_2 = [];

while (~isempty(A))

	temp_A = A(1);
	temp_B = B(1);
	temp_C = C(1);
	total_sum = 0;
	I_A = find(A==temp_A);
	I_B = find(B==temp_B);
	I_AB = intersect(I_A, I_B);


	if (isempty(I_AB))
		total_sum = temp_C;
		A_2 = [A_2; temp_A];
		B_2 = [B_2; temp_B];
		C_2 = [C_2; total_sum];
		A(1) = []; 
		B(1) = [];
		C(1) = [];
	else
		for i=length(I_AB):-1:1
			total_sum = total_sum + C(I_AB(i));
			A(I_AB(i)) = [];
			B(I_AB(i)) = [];
			C(I_AB(i)) = [];
		end 
		A_2 = [A_2; temp_A];
		B_2 = [B_2; temp_B];
		C_2 = [C_2; total_sum];
	end 

end


data = [A_2 B_2 C_2]

dlmwrite('out.txt', data, 'delimiter','\t','precision',3)


Возможные пути решения
1) удалить в txt последние 2 столбца (ибо не используются)
2) загнать txt в sql -> обработать там.
3) возможно есть что-то для больших файлов у c++.
4) python?

Подскажите, уважаемые пользователи!
Спасибо.
  • Вопрос задан
  • 783 просмотра
Решения вопроса 1
@kazmiruk
Прогоните файл утилитой sort (если используете linux). На выходе получите файл, который будет отсортирован. А дальше дело техники, файл в память грузить не надо. Читаете построчно и суммируете z. Как только поменялись x или y - обнуляем z и считаем для следующей пары.
Ответ написан
Пригласить эксперта
Ответы на вопрос 5
@abcdefghijklmnopq
функция API операционной системы для маппинга файлов на оперативную память как раз для этих целей подходит.

если есть возможность я бы все равно предварительно подрезал бы (два последних ненужных столбца), например, EmEditor хорошо работает с большими файлами.
Ответ написан
@Tuvan
Если X и Y не слишком большие ,то можно сделать матрицу SUM[X][Y] += Z (аналог матрицы смежности в графах)
Ответ написан
AtomKrieg
@AtomKrieg
Давай я поищу в Google за тебя
Если вам нужно делать это постоянно и скорость важна как воздух, то выбирайте С++. Вариант на c++ примерно такой:
1) Считать весь файл в память.
2) Распарсить каждую строчку (вручную, так как у встроенных функций есть оверхед)
3) Для подсчета суммы используем контейнер
map<pair<int, int>, int> result;
get_parse(val1, val2, val3);
result[std::make_pair(val1, val2)] += val3;

4) Пишем весь контейнер в память (ручной функцией), сохраняем на диск.

SQL будет точно самым медленным решением. Если хотите воспользоваться питоном, то используйте библиотеку Pandas (stackoverflow.com/questions/15570099/pandas-pivot-... или Numpy (но тогда без текстов, сами пример ищите)
Ответ написан
@mantyr
Пишу много Golang кода с удовольствием:)
1) удалить в txt последние 2 столбца (ибо не используются)
- если есть возможность не обрабатывать данные которые не нужны то так и нужно поступить.
2) загнать txt в sql -> обработать там.
- бессмысленное занятие
3) возможно есть что-то для больших файлов у c++.
- суть разбора больших файлов (1, 10, 100, 1000 гигабайт на файл и больше) в том что бы читать его чанками по несколько байт (размер выбирается исходя из задачи) и анализ файла в поточном виде (не загружать его весь в память).

Алгоритм:
1. читаете поточно по N байт
2. при нахождении \n считаете что началась новая строка
3. как только собрали строку - делаете с ней что хотите, в данном случае разбиваете по-пробельно (explode(" ", $str); пример из php, но не суть)
4. закидываете в некий результирующий массив третью ячейку в качестве значения и первые две ячейки в качестве ключа, если данные уже были то суммируете.

Конечно это не спасёт от величины результирующего массива равного количеству уникальных ключей (ячейки x y). Для этого применяют mapReduce, но для вашей задачи он избыточен.

Вариант как избавиться от большого результирующего массива:
1. алгоритм прежний
2. записываете значение в mysql или любую другую базу в виде
INSERT INTO result_table
SET
    key = ".$key.",
    value = ".$value."
ON DUPLICATE KEY UPDATE value = value + ".$value."

Где result_table.key PRIMARY KEY
Ответ написан
@abcd0x00
Я бы сначала разделил исходный файл на несколько разных файлов, где каждый файл хранит одинаковые x y.
Потом каждый из этих файлов по очереди превращал в одну строку и сбрасывал её в общий файл вывода.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы