Perl: эффективность программирования при вычислении коэффициентов корреляции для большого набора данных - PullRequest
3 голосов
/ 23 марта 2009

РЕДАКТИРОВАТЬ: ссылка должна работать сейчас, извините за беспокойство

У меня есть текстовый файл, который выглядит так:

Name, Test 1, Test 2, Test 3, Test 4, Test 5
Bob, 86, 83, 86, 80, 23
Alice, 38, 90, 100, 53, 32
Jill, 49, 53, 63, 43, 23.

Я пишу программу, которая предоставляет этот текстовый файл, она сгенерирует таблицу коэффициентов корреляции Пирсона, которая выглядит следующим образом, где запись (x, y) - это корреляция между человеком x и человеком y:

Name,Bob,Alice,Jill
Bob, 1, 0.567088412588577, 0.899798494392584
Alice, 0.567088412588577, 1, 0.812425393004088
Jill, 0.899798494392584, 0.812425393004088, 1

Моя программа работает, за исключением того, что набор данных, который я передаю, имеет 82 столбца и, что более важно, 54000 строк. Когда я запускаю свою программу прямо сейчас, она невероятно медленная, и у меня появляется ошибка нехватки памяти. Есть ли способ, которым я могу прежде всего удалить любую возможность ошибки нехватки памяти и, возможно, заставить программу работать немного эффективнее? Код здесь: код .

Спасибо за вашу помощь,
Jack

Редактировать: Если кто-то еще пытается выполнить крупномасштабные вычисления, преобразуйте ваши данные в формат hdf5. Это то, что я сделал, чтобы решить эту проблему.

Ответы [ 7 ]

4 голосов
/ 24 марта 2009

Вы искали CPAN? Мой собственный поиск дал другой метод gsl_stats_correlation для вычисления корреляции Пирсона. Этот находится в Math :: GSL :: Statisics . Этот модуль связан с научной библиотекой GNU.

gsl_stats_correlation ($ data1, $ stride1, $ data2, $ stride2, $ n) - эта функция эффективно вычисляет коэффициент корреляции Пирсона между ссылками на массив $ data1 и $ data2, которые оба должны иметь одинаковую длину $ n. r = cov (x, y) / (\ Hat \ sigma_x \ Hat \ sigma_y) = {1 / (n-1) \ sum (x_i - \ Hat x) (y_i - \ Hat y) \ over \ sqrt {1 / (n-1) \ sum (x_i - \ Hat x) ^ 2} \ sqrt {1 / (n-1) \ sum (y_i - \ Hat y) ^ 2}}

4 голосов
/ 23 марта 2009

Взгляните на Tie :: File , чтобы справиться с большим использованием памяти, когда ваши входные и выходные файлы хранятся в памяти.

4 голосов
/ 23 марта 2009

Вам нужно будет сделать не менее 54000 ^ 2 * 82 вычислений и сравнений. Конечно, это займет много времени. Вы держите все в памяти? Это тоже будет довольно большим. Это будет медленнее, но он может использовать меньше памяти, если вы можете хранить пользователей в базе данных и вычислять одного пользователя по отношению ко всем остальным, а затем переходить к следующему и делать это против всех остальных вместо одного массивного массива или хэша.

3 голосов
/ 24 марта 2009

Вы можете посмотреть на PDL :

PDL («Язык данных Perl») дает стандартная Perl способность компактно хранить и быстро манипулировать большие N-мерные массивы данных, которые хлеб с маслом научного вычислительное

.

2 голосов
/ 24 марта 2009

По сути, Пол Томблин дал вам ответ: это большой расчет, так что это займет много времени. Это много данных, поэтому это займет много памяти.

Однако, может быть одна ошибка: если вы используете perl 5.10.0, ваши списки в начале каждого метода могут быть жертвами незначительной ошибки производительности в этой версии perl (см. поток perlmonks ).

Пара незначительных очков:

Распечатка может на самом деле несколько замедлить программу, в зависимости от того, куда она идет.

Нет необходимости повторно открывать выходной файл для каждой строки! Просто сделайте что-то вроде этого:

open FILE, ">", "file.txt" or die $!;
print FILE "Name, ", join(", ", 0..$#{$correlations[0]}+1), "\n";
my $rowno = 1;
foreach my $row (@correlations) {
  print FILE "$rowno, " . join(", ", @$row) . "\n";
  $rowno++;
}
close FILE;

Наконец, хотя я и использую Perl всякий раз, когда могу, с программой и набором данных, которые вы описываете, это может быть самый простой способ просто использовать C ++ с его iostreams (что делает синтаксический анализ достаточно простым) для этой задачи.

Обратите внимание, что все это лишь незначительная оптимизация. Там нет алгоритмического усиления.

1 голос
/ 23 марта 2009

Я недостаточно знаю, что вы пытаетесь сделать, чтобы дать хороший совет по реализации, но вы можете посмотреть на Statistics::LSNoHistory, он утверждает, что имеет метод pearson_r, который возвращает Пирсона Коэффициент корреляции r.

0 голосов
/ 10 октября 2010

В дополнение к приведенному выше комментарию о PDL приведен код, позволяющий довольно эффективно рассчитать таблицу корреляции даже для очень больших наборов данных:

use PDL::Stats; # this useful module can be downloaded from CPAN
my $data = random(82, 5400); # your data should replace this
my $table = $data->corr_table(); # that's all, really

Возможно, вам потребуется установить $PDL::BIGPDL = 1; в заголовке вашего скрипта и убедиться, что вы запускаете его на машине с ОЧЕНЬ большим количеством памяти. Само вычисление достаточно быстрое, на моем ноутбуке таблица 82 x 5400 заняла всего несколько секунд.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...