11
11
except ImportError : # pragma: no cover
12
12
_USE_BOTTLENECK = False
13
13
14
- def nansum (values , axis = None , skipna = True , copy = True ):
14
+ def _bottleneck_switch (bn_name , alt , ** kwargs ):
15
+ bn_func = getattr (bn , bn_name )
16
+ def f (values , axis = None , skipna = True ):
17
+ try :
18
+ if _USE_BOTTLENECK and skipna :
19
+ result = bn_func (values , axis = axis , ** kwargs )
20
+ # prefer to treat inf/-inf as NA
21
+ if _has_infs (result ):
22
+ result = alt (values , axis = axis , skipna = skipna , ** kwargs )
23
+ else :
24
+ result = alt (values , axis = axis , skipna = skipna , ** kwargs )
25
+ except Exception :
26
+ result = alt (values , axis = axis , skipna = skipna , ** kwargs )
27
+
28
+ return result
29
+
30
+ return f
31
+
32
+ def _has_infs (result ):
33
+ if isinstance (result , np .ndarray ):
34
+ if result .dtype == 'f8' :
35
+ return lib .has_infs_f8 (result )
36
+ elif result .dtype == 'f4' :
37
+ return lib .has_infs_f4 (result )
38
+ else : # pragma: no cover
39
+ raise TypeError ('Only suppose float32/64 here' )
40
+ else :
41
+ return np .isinf (result ) or np .isneginf (result )
42
+
43
+ def _nansum (values , axis = None , skipna = True ):
15
44
mask = isnull (values )
16
45
17
46
if skipna and not issubclass (values .dtype .type , np .integer ):
18
- if copy :
19
- values = values .copy ()
47
+ values = values .copy ()
20
48
np .putmask (values , mask , 0 )
21
49
22
50
the_sum = values .sum (axis )
23
51
the_sum = _maybe_null_out (the_sum , axis , mask )
24
52
25
53
return the_sum
26
54
27
- def nanmean (values , axis = None , skipna = True , copy = True ):
55
+ def _nanmean (values , axis = None , skipna = True ):
28
56
mask = isnull (values )
29
57
30
58
if skipna and not issubclass (values .dtype .type , np .integer ):
31
- if copy :
32
- values = values .copy ()
59
+ values = values .copy ()
33
60
np .putmask (values , mask , 0 )
34
61
35
62
the_sum = values .sum (axis )
@@ -44,7 +71,7 @@ def nanmean(values, axis=None, skipna=True, copy=True):
44
71
the_mean = the_sum / count if count > 0 else np .nan
45
72
return the_mean
46
73
47
- def nanmedian (values , axis = None , skipna = True , copy = True ):
74
+ def _nanmedian (values , axis = None , skipna = True ):
48
75
def get_median (x ):
49
76
mask = notnull (x )
50
77
if not skipna and not mask .all ():
@@ -59,7 +86,7 @@ def get_median(x):
59
86
else :
60
87
return get_median (values )
61
88
62
- def nanvar (values , axis = None , skipna = True , copy = True , ddof = 1 ):
89
+ def _nanvar (values , axis = None , skipna = True , ddof = 1 ):
63
90
mask = isnull (values )
64
91
65
92
if axis is not None :
@@ -68,52 +95,17 @@ def nanvar(values, axis=None, skipna=True, copy=True, ddof=1):
68
95
count = float (values .size - mask .sum ())
69
96
70
97
if skipna :
71
- if copy :
72
- values = values .copy ()
98
+ values = values .copy ()
73
99
np .putmask (values , mask , 0 )
74
100
75
101
X = values .sum (axis )
76
102
XX = (values ** 2 ).sum (axis )
77
103
return (XX - X ** 2 / count ) / (count - ddof )
78
104
79
- def nanskew (values , axis = None , skipna = True , copy = True ):
80
- if not isinstance (values .dtype .type , np .floating ):
81
- values = values .astype ('f8' )
82
-
83
- mask = isnull (values )
84
- count = _get_counts (mask , axis )
85
-
86
- if skipna :
87
- if copy :
88
- values = values .copy ()
89
- np .putmask (values , mask , 0 )
90
-
91
- A = values .sum (axis ) / count
92
- B = (values ** 2 ).sum (axis ) / count - A ** 2
93
- C = (values ** 3 ).sum (axis ) / count - A ** 3 - 3 * A * B
94
-
95
- # floating point error
96
- B = _zero_out_fperr (B )
97
- C = _zero_out_fperr (C )
98
-
99
- result = ((np .sqrt ((count ** 2 - count )) * C ) /
100
- ((count - 2 ) * np .sqrt (B ) ** 3 ))
101
-
102
- if isinstance (result , np .ndarray ):
103
- result = np .where (B == 0 , 0 , result )
104
- result [count < 3 ] = np .nan
105
- return result
106
- else :
107
- result = 0 if B == 0 else result
108
- if count < 3 :
109
- return np .nan
110
- return result
111
-
112
- def nanmin (values , axis = None , skipna = True , copy = True ):
105
+ def _nanmin (values , axis = None , skipna = True ):
113
106
mask = isnull (values )
114
107
if skipna and not issubclass (values .dtype .type , np .integer ):
115
- if copy :
116
- values = values .copy ()
108
+ values = values .copy ()
117
109
np .putmask (values , mask , np .inf )
118
110
# numpy 1.6.1 workaround in Python 3.x
119
111
if (values .dtype == np .object_
@@ -129,11 +121,10 @@ def nanmin(values, axis=None, skipna=True, copy=True):
129
121
130
122
return _maybe_null_out (result , axis , mask )
131
123
132
- def nanmax (values , axis = None , skipna = True , copy = True ):
124
+ def _nanmax (values , axis = None , skipna = True ):
133
125
mask = isnull (values )
134
126
if skipna and not issubclass (values .dtype .type , np .integer ):
135
- if copy :
136
- values = values .copy ()
127
+ values = values .copy ()
137
128
np .putmask (values , mask , - np .inf )
138
129
# numpy 1.6.1 workaround in Python 3.x
139
130
if (values .dtype == np .object_
@@ -149,15 +140,6 @@ def nanmax(values, axis=None, skipna=True, copy=True):
149
140
result = values .max (axis )
150
141
return _maybe_null_out (result , axis , mask )
151
142
152
- def nanprod (values , axis = None , skipna = True , copy = True ):
153
- mask = isnull (values )
154
- if skipna and not issubclass (values .dtype .type , np .integer ):
155
- if copy :
156
- values = values .copy ()
157
- values [mask ] = 1
158
- result = values .prod (axis )
159
- return _maybe_null_out (result , axis , mask )
160
-
161
143
def nanargmax (values , axis = None , skipna = True ):
162
144
"""
163
145
Returns -1 in the NA case
@@ -182,6 +164,53 @@ def nanargmin(values, axis=None, skipna=True):
182
164
result = _maybe_arg_null_out (result , axis , mask , skipna )
183
165
return result
184
166
167
+ nansum = _bottleneck_switch ('nansum' , _nansum )
168
+ nanmean = _bottleneck_switch ('nanmean' , _nanmean )
169
+ nanmedian = _bottleneck_switch ('nanmedian' , _nanmedian )
170
+ nanvar = _bottleneck_switch ('nanvar' , _nanvar , ddof = 1 )
171
+ nanmin = _bottleneck_switch ('nanmin' , _nanmin )
172
+ nanmax = _bottleneck_switch ('nanmax' , _nanmax )
173
+
174
+ def nanskew (values , axis = None , skipna = True ):
175
+ if not isinstance (values .dtype .type , np .floating ):
176
+ values = values .astype ('f8' )
177
+
178
+ mask = isnull (values )
179
+ count = _get_counts (mask , axis )
180
+
181
+ if skipna :
182
+ values = values .copy ()
183
+ np .putmask (values , mask , 0 )
184
+
185
+ A = values .sum (axis ) / count
186
+ B = (values ** 2 ).sum (axis ) / count - A ** 2
187
+ C = (values ** 3 ).sum (axis ) / count - A ** 3 - 3 * A * B
188
+
189
+ # floating point error
190
+ B = _zero_out_fperr (B )
191
+ C = _zero_out_fperr (C )
192
+
193
+ result = ((np .sqrt ((count ** 2 - count )) * C ) /
194
+ ((count - 2 ) * np .sqrt (B ) ** 3 ))
195
+
196
+ if isinstance (result , np .ndarray ):
197
+ result = np .where (B == 0 , 0 , result )
198
+ result [count < 3 ] = np .nan
199
+ return result
200
+ else :
201
+ result = 0 if B == 0 else result
202
+ if count < 3 :
203
+ return np .nan
204
+ return result
205
+
206
+ def nanprod (values , axis = None , skipna = True ):
207
+ mask = isnull (values )
208
+ if skipna and not issubclass (values .dtype .type , np .integer ):
209
+ values = values .copy ()
210
+ values [mask ] = 1
211
+ result = values .prod (axis )
212
+ return _maybe_null_out (result , axis , mask )
213
+
185
214
def _maybe_arg_null_out (result , axis , mask , skipna ):
186
215
# helper function for nanargmin/nanargmax
187
216
if axis is None :
0 commit comments