14
14
_ensure_int64 ,
15
15
needs_i8_conversion ,
16
16
is_scalar ,
17
+ is_number ,
17
18
is_integer , is_bool ,
18
19
is_bool_dtype ,
19
20
is_numeric_dtype ,
@@ -4104,6 +4105,22 @@ def isnull(self):
4104
4105
def notnull (self ):
4105
4106
return notnull (self ).__finalize__ (self )
4106
4107
4108
+ def _clip_with_scalar (self , lower , upper ):
4109
+
4110
+ if ((lower is not None and np .any (isnull (lower ))) or
4111
+ (upper is not None and np .any (isnull (upper )))):
4112
+ raise ValueError ("Cannot use an NA value as a clip threshold" )
4113
+
4114
+ result = self .values
4115
+ mask = isnull (result )
4116
+ if upper is not None :
4117
+ result = np .where (result >= upper , upper , result )
4118
+ if lower is not None :
4119
+ result = np .where (result <= lower , lower , result )
4120
+ result [mask ] = np .nan
4121
+ return self ._constructor (
4122
+ result , ** self ._construct_axes_dict ()).__finalize__ (self )
4123
+
4107
4124
def clip (self , lower = None , upper = None , axis = None , * args , ** kwargs ):
4108
4125
"""
4109
4126
Trim values at input threshold(s).
@@ -4122,26 +4139,29 @@ def clip(self, lower=None, upper=None, axis=None, *args, **kwargs):
4122
4139
Examples
4123
4140
--------
4124
4141
>>> df
4125
- 0 1
4142
+ 0 1
4126
4143
0 0.335232 -1.256177
4127
4144
1 -1.367855 0.746646
4128
4145
2 0.027753 -1.176076
4129
4146
3 0.230930 -0.679613
4130
4147
4 1.261967 0.570967
4148
+
4131
4149
>>> df.clip(-1.0, 0.5)
4132
4150
0 1
4133
4151
0 0.335232 -1.000000
4134
4152
1 -1.000000 0.500000
4135
4153
2 0.027753 -1.000000
4136
4154
3 0.230930 -0.679613
4137
4155
4 0.500000 0.500000
4156
+
4138
4157
>>> t
4139
4158
0 -0.3
4140
4159
1 -0.2
4141
4160
2 -0.1
4142
4161
3 0.0
4143
4162
4 0.1
4144
4163
dtype: float64
4164
+
4145
4165
>>> df.clip(t, t + 1, axis=0)
4146
4166
0 1
4147
4167
0 0.335232 -0.300000
@@ -4160,6 +4180,11 @@ def clip(self, lower=None, upper=None, axis=None, *args, **kwargs):
4160
4180
if is_scalar (lower ) and is_scalar (upper ):
4161
4181
lower , upper = min (lower , upper ), max (lower , upper )
4162
4182
4183
+ # fast-path for scalars
4184
+ if ((lower is None or (is_scalar (lower ) and is_number (lower ))) and
4185
+ (upper is None or (is_scalar (upper ) and is_number (upper )))):
4186
+ return self ._clip_with_scalar (lower , upper )
4187
+
4163
4188
result = self
4164
4189
if lower is not None :
4165
4190
result = result .clip_lower (lower , axis )
@@ -4189,6 +4214,9 @@ def clip_upper(self, threshold, axis=None):
4189
4214
if np .any (isnull (threshold )):
4190
4215
raise ValueError ("Cannot use an NA value as a clip threshold" )
4191
4216
4217
+ if is_scalar (threshold ) and is_number (threshold ):
4218
+ return self ._clip_with_scalar (None , threshold )
4219
+
4192
4220
subset = self .le (threshold , axis = axis ) | isnull (self )
4193
4221
return self .where (subset , threshold , axis = axis )
4194
4222
@@ -4213,6 +4241,9 @@ def clip_lower(self, threshold, axis=None):
4213
4241
if np .any (isnull (threshold )):
4214
4242
raise ValueError ("Cannot use an NA value as a clip threshold" )
4215
4243
4244
+ if is_scalar (threshold ) and is_number (threshold ):
4245
+ return self ._clip_with_scalar (threshold , None )
4246
+
4216
4247
subset = self .ge (threshold , axis = axis ) | isnull (self )
4217
4248
return self .where (subset , threshold , axis = axis )
4218
4249
0 commit comments