NumPy: вычислить средние значения с удаленными NaN - PullRequest
39 голосов
/ 30 марта 2011

Как я могу вычислить средние значения матрицы вдоль матрицы, но удалить nan значения из расчета? (Для R людей, подумайте na.rm = TRUE).

Вот мой [не] рабочий пример:

import numpy as np
dat = np.array([[1, 2, 3],
                [4, 5, np.nan],
                [np.nan, 6, np.nan],
                [np.nan, np.nan, np.nan]])
print(dat)
print(dat.mean(1))  # [  2.  nan  nan  nan]

При удалении NaN мой ожидаемый результат будет:

array([ 2.,  4.5,  6.,  nan])

Ответы [ 12 ]

35 голосов
/ 30 марта 2011

Я думаю, что вы хотите получить маскированный массив:

dat = np.array([[1,2,3], [4,5,nan], [nan,6,nan], [nan,nan,nan]])
mdat = np.ma.masked_array(dat,np.isnan(dat))
mm = np.mean(mdat,axis=1)
print mm.filled(np.nan) # the desired answer

Редактировать: Объединение всех временных данных

   from timeit import Timer

    setupstr="""
import numpy as np
from scipy.stats.stats import nanmean    
dat = np.random.normal(size=(1000,1000))
ii = np.ix_(np.random.randint(0,99,size=50),np.random.randint(0,99,size=50))
dat[ii] = np.nan
"""  

    method1="""
mdat = np.ma.masked_array(dat,np.isnan(dat))
mm = np.mean(mdat,axis=1)
mm.filled(np.nan)    
"""

    N = 2
    t1 = Timer(method1, setupstr).timeit(N)
    t2 = Timer("[np.mean([l for l in d if not np.isnan(l)]) for d in dat]", setupstr).timeit(N)
    t3 = Timer("np.array([r[np.isfinite(r)].mean() for r in dat])", setupstr).timeit(N)
    t4 = Timer("np.ma.masked_invalid(dat).mean(axis=1)", setupstr).timeit(N)
    t5 = Timer("nanmean(dat,axis=1)", setupstr).timeit(N)

    print 'Time: %f\tRatio: %f' % (t1,t1/t1 )
    print 'Time: %f\tRatio: %f' % (t2,t2/t1 )
    print 'Time: %f\tRatio: %f' % (t3,t3/t1 )
    print 'Time: %f\tRatio: %f' % (t4,t4/t1 )
    print 'Time: %f\tRatio: %f' % (t5,t5/t1 )

Возвращает:

Time: 0.045454  Ratio: 1.000000
Time: 8.179479  Ratio: 179.950595
Time: 0.060988  Ratio: 1.341755
Time: 0.070955  Ratio: 1.561029
Time: 0.065152  Ratio: 1.433364
18 голосов
/ 30 марта 2011

Если производительность имеет значение, вы должны использовать bottleneck.nanmean() вместо:

http://pypi.python.org/pypi/Bottleneck

12 голосов
/ 30 марта 2011

При условии, что у вас также установлен SciPy:

http://www.scipy.org/doc/api_docs/SciPy.stats.stats.html#nanmean

8 голосов
/ 08 ноября 2011

Обходной путь всегда можно найти во что-то вроде:

numpy.nansum(dat, axis=1) / numpy.sum(numpy.isfinite(dat), axis=1)

У Numpy 2.0 numpy.mean есть опция skipna, которая должна об этом позаботиться.

8 голосов
/ 30 марта 2011

Маскированный массив с отфильтрованными nans также может быть создан на лету:

print np.ma.masked_invalid(dat).mean(1)
3 голосов
/ 13 января 2012

Это основано на решении, предложенном JoshAdel.

Определите следующую функцию:

def nanmean(data, **args):
    return numpy.ma.filled(numpy.ma.masked_array(data,numpy.isnan(data)).mean(**args), fill_value=numpy.nan)

Пример использования:

data = [[0, 1, numpy.nan], [8, 5, 1]]
data = numpy.array(data)
print data
print nanmean(data)
print nanmean(data, axis=0)
print nanmean(data, axis=1)

Распечатает:

[[  0.   1.  nan]
 [  8.   5.   1.]]

3.0

[ 4.  3.  1.]

[ 0.5         4.66666667]
2 голосов
/ 06 марта 2016

Начиная с версии 1.8 (выпущена 2013-10-30), nanmean делает именно то, что вам нужно:

>>> import numpy as np
>>> np.nanmean(np.array([1.5, 3.5, np.nan]))
2.5
2 голосов
/ 29 января 2014

Как насчет использования Панд для этого:

import numpy as np
import pandas as pd
dat = np.array([[1, 2, 3], [4, 5, np.nan], [np.nan, 6, np.nan], [np.nan, np.nan, np.nan]])
print dat
print dat.mean(1)

df = pd.DataFrame(dat)
print df.mean(axis=1)

Дает:

0    2.0
1    4.5
2    6.0
3    NaN
1 голос
/ 05 декабря 2013

Или вы используете недавно загруженный laxarray, который среди прочего является оберткой для замаскированных массивов.

import laxarray as la
la.array(dat).mean(axis=1)

в соответствии с протоколом JoshAdel, я получаю:

Time: 0.048791  Ratio: 1.000000   
Time: 0.062242  Ratio: 1.275689   # laxarray's one-liner

Так что laxarray немного медленнее(нужно будет проверить почему, может быть исправимо), но гораздо проще в использовании и позволяет маркировать размеры строками.

проверить: https://github.com/perrette/laxarray

РЕДАКТИРОВАТЬ: Я проверил с другим модулем, "ла", Ларри, который бьет все тесты:

import la
la.larry(dat).mean(axis=1)

By hand, Time: 0.049013 Ratio: 1.000000
Larry,   Time: 0.005467 Ratio: 0.111540
laxarray Time: 0.061751 Ratio: 1.259889

Впечатляет!

0 голосов
/ 27 сентября 2017
# I suggest you this way:
import numpy as np
dat  = np.array([[1, 2, 3], [4, 5, np.nan], [np.nan, 6, np.nan], [np.nan, np.nan, np.nan]])
dat2 = np.ma.masked_invalid(dat)
print np.mean(dat2, axis=1)   
...