NumCpp  2.4.0
A Templatized Header Only C++ Implementation of the Python NumPy Library
nanpercentile.hpp
Go to the documentation of this file.
1 #pragma once
29 
33 #include "NumCpp/Core/Shape.hpp"
34 #include "NumCpp/Core/Types.hpp"
38 #include "NumCpp/NdArray.hpp"
40 
41 #include <algorithm>
42 #include <cmath>
43 #include <string>
44 #include <vector>
45 
46 namespace nc
47 {
48  //============================================================================
49  // Method Description:
61  template<typename dtype>
62  NdArray<dtype> nanpercentile(const NdArray<dtype>& inArray, double inPercentile,
63  Axis inAxis = Axis::NONE, const std::string& inInterpMethod = "linear")
64  {
65  STATIC_ASSERT_FLOAT(dtype);
66 
67  if (inPercentile < 0.0 || inPercentile > 100.0)
68  {
69  THROW_INVALID_ARGUMENT_ERROR("input percentile value must be of the range [0, 100].");
70  }
71 
72  if (inInterpMethod != "linear" &&
73  inInterpMethod != "lower" &&
74  inInterpMethod != "higher" &&
75  inInterpMethod != "nearest" &&
76  inInterpMethod != "midpoint")
77  {
78  std::string errStr = "input interpolation method is not a vaid option.\n";
79  errStr += "\tValid options are 'linear', 'lower', 'higher', 'nearest', 'midpoint'.";
81  }
82 
83  switch (inAxis)
84  {
85  case Axis::NONE:
86  {
87  if (utils::essentiallyEqual(inPercentile, 0.0))
88  {
89  for (auto value : inArray)
90  {
91  if (!isnan(value))
92  {
93  NdArray<dtype> returnArray = { value };
94  return returnArray;
95  }
96  }
97  return NdArray<dtype>(0);
98  }
99 
100  if (utils::essentiallyEqual(inPercentile, 100.0))
101  {
102  for (int32 i = static_cast<int32>(inArray.size()) - 1; i > -1; --i)
103  {
104  if (!isnan(inArray[i]))
105  {
106  NdArray<dtype> returnArray = { inArray[i] };
107  return returnArray;
108  }
109  }
110  return NdArray<dtype>(0);
111  }
112 
113  std::vector<double> arrayCopy;
114  uint32 numNonNan = 0;
115  for (auto value : inArray)
116  {
117  if (!isnan(value))
118  {
119  arrayCopy.push_back(value);
120  ++numNonNan;
121  }
122  }
123 
124  if (arrayCopy.size() < 2)
125  {
126  return NdArray<dtype>(0);
127  }
128 
129  const auto i = static_cast<int32>(std::floor(static_cast<double>(numNonNan - 1) * inPercentile / 100.0));
130  const auto indexLower = static_cast<uint32>(clip<uint32>(i, 0, numNonNan - 2));
131 
132  stl_algorithms::sort(arrayCopy.begin(), arrayCopy.end());
133 
134  if (inInterpMethod == "linear")
135  {
136  const double percentI = static_cast<double>(indexLower) / static_cast<double>(numNonNan - 1);
137  const double fraction = (inPercentile / 100.0 - percentI) /
138  (static_cast<double>(indexLower + 1) / static_cast<double>(numNonNan - 1) - percentI);
139 
140  const double returnValue = arrayCopy[indexLower] + (arrayCopy[indexLower + 1] - arrayCopy[indexLower]) * fraction;
141  NdArray<dtype> returnArray = { returnValue };
142  return returnArray;
143  }
144 
145  if (inInterpMethod == "lower")
146  {
147  NdArray<dtype> returnArray = { arrayCopy[indexLower] };
148  return returnArray;
149  }
150 
151  if (inInterpMethod == "higher")
152  {
153  NdArray<dtype> returnArray = { arrayCopy[indexLower + 1] };
154  return returnArray;
155  }
156 
157  if (inInterpMethod == "nearest")
158  {
159  const double percent = inPercentile / 100.0;
160  const double percent1 = static_cast<double>(indexLower) / static_cast<double>(numNonNan - 1);
161  const double percent2 = static_cast<double>(indexLower + 1) / static_cast<double>(numNonNan - 1);
162  const double diff1 = percent - percent1;
163  const double diff2 = percent2 - percent;
164 
165  switch (argmin<double>({ diff1, diff2 }).item())
166  {
167  case 0:
168  {
169  NdArray<dtype> returnArray = { arrayCopy[indexLower] };
170  return returnArray;
171  }
172  case 1:
173  {
174  NdArray<dtype> returnArray = { arrayCopy[indexLower + 1] };
175  return returnArray;
176  }
177  }
178  }
179 
180  if (inInterpMethod == "midpoint")
181  {
182  NdArray<dtype> returnArray = { (arrayCopy[indexLower] + arrayCopy[indexLower + 1]) / 2.0 };
183  return returnArray;
184  }
185 
186  THROW_INVALID_ARGUMENT_ERROR("intperpolation method has not been implemented: " + inInterpMethod);
187 
188  // this isn't actually possible, just putting this here to get rid
189  // of the compiler warning.
190  return NdArray<dtype>(0);
191  }
192  case Axis::COL:
193  {
194  const Shape inShape = inArray.shape();
195 
196  NdArray<dtype> returnArray(1, inShape.rows);
197  for (uint32 row = 0; row < inShape.rows; ++row)
198  {
199  NdArray<dtype> outValue = nanpercentile(NdArray<dtype>(inArray.cbegin(row), inArray.cend(row)),
200  inPercentile, Axis::NONE, inInterpMethod);
201 
202  if (outValue.size() == 1)
203  {
204  returnArray[row] = outValue.item();
205  }
206  else
207  {
208  returnArray[row] = constants::nan;
209  }
210  }
211 
212  return returnArray;
213  }
214  case Axis::ROW:
215  {
216  NdArray<dtype> arrayTrans = inArray.transpose();
217  const Shape inShape = arrayTrans.shape();
218 
219  NdArray<dtype> returnArray(1, inShape.rows);
220  for (uint32 row = 0; row < inShape.rows; ++row)
221  {
222  NdArray<dtype> outValue = nanpercentile(NdArray<dtype>(arrayTrans.cbegin(row), arrayTrans.cend(row)),
223  inPercentile, Axis::NONE, inInterpMethod);
224 
225  if (outValue.size() == 1)
226  {
227  returnArray[row] = outValue.item();
228  }
229  else
230  {
231  returnArray[row] = constants::nan;
232  }
233  }
234 
235  return returnArray;
236  }
237  default:
238  {
239  THROW_INVALID_ARGUMENT_ERROR("Unimplemented axis type.");
240  return {}; // get rid of compiler warning
241  }
242  }
243  }
244 } // namespace nc
StaticAsserts.hpp
nc::NdArray::item
value_type item() const
Definition: NdArrayCore.hpp:2975
nc::NdArray::shape
Shape shape() const noexcept
Definition: NdArrayCore.hpp:4356
nc::Axis::NONE
@ NONE
nc::int32
std::int32_t int32
Definition: Types.hpp:36
Error.hpp
nc::Axis::ROW
@ ROW
argmin.hpp
nc::nanpercentile
NdArray< dtype > nanpercentile(const NdArray< dtype > &inArray, double inPercentile, Axis inAxis=Axis::NONE, const std::string &inInterpMethod="linear")
Definition: nanpercentile.hpp:62
nc::utils::essentiallyEqual
bool essentiallyEqual(dtype inValue1, dtype inValue2) noexcept
Definition: essentiallyEqual.hpp:52
clip.hpp
nc::NdArray::transpose
NdArray< dtype > transpose() const
Definition: NdArrayCore.hpp:4652
nc::NdArray< dtype >
nc::uint32
std::uint32_t uint32
Definition: Types.hpp:40
nc::floor
dtype floor(dtype inValue) noexcept
Definition: floor.hpp:48
NdArray.hpp
nc::Shape
A Shape Class for NdArrays.
Definition: Core/Shape.hpp:40
STATIC_ASSERT_FLOAT
#define STATIC_ASSERT_FLOAT(dtype)
Definition: StaticAsserts.hpp:43
isnan.hpp
nc::NdArray::size
size_type size() const noexcept
Definition: NdArrayCore.hpp:4370
nc::NdArray::cend
const_iterator cend() const noexcept
Definition: NdArrayCore.hpp:1487
nc::Axis
Axis
Enum To describe an axis.
Definition: Types.hpp:46
nc::constants::nan
const double nan
NaN.
Definition: Constants.hpp:44
Shape.hpp
nc
Definition: Coordinate.hpp:44
nc::Shape::rows
uint32 rows
Definition: Core/Shape.hpp:44
essentiallyEqual.hpp
THROW_INVALID_ARGUMENT_ERROR
#define THROW_INVALID_ARGUMENT_ERROR(msg)
Definition: Error.hpp:36
nc::NdArray::cbegin
const_iterator cbegin() const noexcept
Definition: NdArrayCore.hpp:1143
nc::stl_algorithms::sort
void sort(RandomIt first, RandomIt last) noexcept
Definition: StlAlgorithms.hpp:629
StlAlgorithms.hpp
Types.hpp
nc::Axis::COL
@ COL
nc::isnan
bool isnan(dtype inValue) noexcept
Definition: isnan.hpp:51