Я ставлю это как ответ, так как в комментарии больше, чем уместится, хотя это может быть и не полностью. Есть две подозрительные вещи: во-первых, процентиль должен нормально работать на матрице 20 ГБ, если на вашей машине доступно 200 ГБ оперативной памяти. Это много памяти, поэтому начните изучать, что еще может быть использовано. Начните с top
- есть ли другой процесс или ваша программа Python использует все это?
Вторым подозрительным моментом является то, что документация для utils.percentile
не соответствует фактическому поведению. Вот соответствующие биты из кода, с которым вы связались:
def percentile(matrix, p):
"""
Estimation of percentile without zeros.
....
Returns
-------
float
Calculated percentile.
"""
return np.percentile(matrix[np.any(matrix > 0, axis=1)], p, axis=0)
На самом деле он возвращает (по столбцам) процентиль, рассчитанный для строк, которые не являются всеми нулями. edit Это строки, которые содержат хотя бы один положительный элемент. Если значения неотрицательны, это одно и то же, но в целом это будет совсем другой результат.
np.any(matrix > 0, axis=1)
возвращает логический массив для индексных строк, которые не являются всеми нулями. Например
>>> np.any(array([[3, 4], [0, 0]]) > 0, axis=1)
array([ True, False])
>>> np.any(array([[3, 4], [1, 0]]) > 0, axis=1)
array([ True, True])
>>> np.any(array([[3, 0], [1, 0]]) > 0, axis=1)
array([ True, True])
Этот массив используется для индексации matrix
, который выбирает только те строки, которые не являются всеми нулями, и возвращает их.
Вам следует прочитать множество документов для индексации , если вы не знакомы с этим способом индексации.
Вычисление, которое занимает много памяти - matrix > 0
создает логический массив того же размера, что и матрица, затем индексирование создает копию matrix
, которая, вероятно, содержит большинство строк.
Так, вероятно, 2-4 ГБ для логического массива и около 20 ГБ для копии.
Это можно уменьшить,
## Find rows with all zeros, one row at a time to reduce memory
mask = [np.any(r > 0) for r in matrix]
## Find percentile for each column, excluding rows with all zeros
perc = [np.percentile(c[mask], p) for c in matrix.T]
Однако, как указывалось ранее, это не соответствует документации по функции.
Может быть причина для этой логики, но она странная.
Если вы не знаете причину этого, вы можете позвонить np.percentile
напрямую - просто убедитесь, что он возвращает близкое значение для меньшего подмножества ваших данных.
Также есть nanpercentile
, который можно использовать таким же образом, но игнорирует значения nan
.
Вы можете использовать логическое индексирование, чтобы заменить значения, которые вы не хотите включать, на nan
(т.е. matrix[matrix < 0] = np.nan
), а затем вызвать его.