Новое решение
Посмотрев на ответ Джо Кингтона, я решил заглянуть в код corrcoef()
и вдохновился им на выполнение следующей реализации.
ms = data.mean(axis=1)[(slice(None,None,None),None)]
datam = data - ms
datass = np.sqrt(scipy.stats.ss(datam,axis=1))
for i in xrange(rows):
temp = np.dot(datam[i:],datam[i].T)
rs = temp / (datass[i:]*datass[i])
Каждый проходной цикл генерирует коэффициенты Пирсона между строкой i и строкой i до последней строки. Это очень быстро. Это как минимум в 1,5 раза быстрее, чем при использовании только corrcoef()
, потому что он не требует избыточного вычисления коэффициентов и некоторых других вещей. Это также будет быстрее и не вызовет проблем с памятью с матрицей в 50 000 строк, потому что тогда вы можете либо сохранить каждый набор r, либо обработать их перед созданием другого набора. Не сохраняя ни одного долгосрочного кода, я смог заставить вышеуказанный код работать на множестве случайно сгенерированных данных размером 50 000 x 10 за минуту на моем довольно новом ноутбуке.
Старое решение
Во-первых, я бы не советовал распечатывать буквы r на экране. Для 100 строк (10 столбцов) это разница составляет 19,79 секунды при печати и 0,301 секунды без использования кода. Просто сохраните r и используйте их позже, если хотите, или выполните некоторую обработку по мере продвижения, например, для поиска самых больших r.
Во-вторых, вы можете получить некоторую экономию, не вычисляя избыточно некоторые количества. Коэффициент Пирсона рассчитывается в scipy с использованием некоторых величин, которые можно предварительно рассчитать, а не вычислять каждый раз, когда используется строка. Кроме того, вы не используете p-значение (которое также возвращается pearsonr()
, поэтому давайте его также рассмотрим. Используя следующий код:
r = np.zeros((rows,rows))
ms = data.mean(axis=1)
datam = np.zeros_like(data)
for i in xrange(rows):
datam[i] = data[i] - ms[i]
datass = scipy.stats.ss(datam,axis=1)
for i in xrange(rows):
for j in xrange(i,rows):
r_num = np.add.reduce(datam[i]*datam[j])
r_den = np.sqrt(datass[i]*datass[j])
r[i,j] = min((r_num / r_den), 1.0)
Я получаю ускорение примерно в 4,8 раза по сравнению с простым кодом scipy, когда я удаляю материал с p-значением - 8,8 раза, если я оставляю материал с p-значением (я использовал 10 столбцов с сотнями строк) ). Я также проверил, что это дает те же результаты. Это не очень большое улучшение, но оно может помочь.
В конечном счете, вы застряли с проблемой, которую вы вычисляете (50000) * (50001) / 2 = 1 250 025 000 коэффициентов Пирсона (если я правильно считаю). Это много. Кстати, на самом деле нет необходимости вычислять коэффициент Пирсона для каждой строки сам по себе (он будет равен 1), но это только спасает вас от вычисления 50 000 коэффициентов Пирсона. С учетом приведенного выше кода, я ожидаю, что для выполнения ваших вычислений потребуется около 4 1/4 часов, если у вас есть 10 столбцов с вашими данными, основанными на моих результатах для небольших наборов данных.
Вы можете получить некоторое улучшение, перенеся приведенный выше код в Cython или что-то подобное. Я ожидаю, что, если вам повезет, вы, возможно, получите 10-кратное улучшение по сравнению с прямым Сципи. Также, как предлагает pyInTheSky, вы можете выполнить несколько многопроцессорных операций.