NumCpp  2.7.0
A Templatized Header Only C++ Implementation of the Python NumPy Library
percentile.hpp
Go to the documentation of this file.
1 #pragma once
29 
33 #include "NumCpp/Core/Shape.hpp"
34 #include "NumCpp/Core/Types.hpp"
37 #include "NumCpp/NdArray.hpp"
39 
40 #include <algorithm>
41 #include <cmath>
42 #include <complex>
43 #include <string>
44 
45 namespace nc
46 {
47  //============================================================================
48  // Method Description:
64  template<typename dtype>
65  NdArray<double> percentile(const NdArray<dtype>& inArray, double inPercentile,
66  Axis inAxis = Axis::NONE, const std::string& inInterpMethod = "linear")
67  {
69 
70  if (inPercentile < 0.0 || inPercentile > 100.0)
71  {
72  THROW_INVALID_ARGUMENT_ERROR("input percentile value must be of the range [0, 100].");
73  }
74 
75  if (inArray.isempty())
76  {
77  return {};
78  }
79  else if (inArray.size() == 1)
80  {
81  NdArray<double> returnArray = { static_cast<double>(inArray.front()) };
82  return returnArray;
83  }
84 
85  if (inInterpMethod != "linear" &&
86  inInterpMethod != "lower" &&
87  inInterpMethod != "higher" &&
88  inInterpMethod != "nearest" &&
89  inInterpMethod != "midpoint")
90  {
91  std::string errStr = "input interpolation method is not a vaid option.\n";
92  errStr += "\tValid options are 'linear', 'lower', 'higher', 'nearest', 'midpoint'.";
94  }
95 
96  switch (inAxis)
97  {
98  case Axis::NONE:
99  {
100  NdArray<double> arrayCopy = inArray.template astype<double>();
101  stl_algorithms::sort(arrayCopy.begin(), arrayCopy.end());
102 
103  if (utils::essentiallyEqual(inPercentile, 0.0))
104  {
105  NdArray<double> returnArray = { arrayCopy.front() };
106  return returnArray;
107  }
108  if (utils::essentiallyEqual(inPercentile, 100.0))
109  {
110  NdArray<double> returnArray = { arrayCopy.back() };
111  return returnArray;
112  }
113 
114  const auto i = static_cast<uint32>(std::floor(static_cast<double>(inArray.size() - 1) * inPercentile / 100.0));
115  const auto indexLower = clip<uint32>(i, 0, inArray.size() - 2);
116 
117  if (inInterpMethod == "linear")
118  {
119  const double percentI = static_cast<double>(indexLower) / static_cast<double>(inArray.size() - 1);
120  const double fraction = (inPercentile / 100.0 - percentI) /
121  (static_cast<double>(indexLower + 1) / static_cast<double>(inArray.size() - 1) - percentI);
122 
123  NdArray<double> returnArray = { arrayCopy[indexLower] + (arrayCopy[indexLower + 1] - arrayCopy[indexLower]) * fraction };
124  return returnArray;
125  }
126 
127  if (inInterpMethod == "lower")
128  {
129  NdArray<double> returnArray = { arrayCopy[indexLower] };
130  return returnArray;
131  }
132 
133  if (inInterpMethod == "higher")
134  {
135  NdArray<double> returnArray = { arrayCopy[indexLower + 1] };
136  return returnArray;
137  }
138 
139  if (inInterpMethod == "nearest")
140  {
141  const double percent = inPercentile / 100.0;
142  const double percent1 = static_cast<double>(indexLower) / static_cast<double>(inArray.size() - 1);
143  const double percent2 = static_cast<double>(indexLower + 1) / static_cast<double>(inArray.size() - 1);
144  const double diff1 = percent - percent1;
145  const double diff2 = percent2 - percent;
146 
147  switch (argmin<double>({ diff1, diff2 }).item())
148  {
149  case 0:
150  {
151  NdArray<double> returnArray = { arrayCopy[indexLower] };
152  return returnArray;
153  }
154  case 1:
155  {
156  NdArray<double> returnArray = { arrayCopy[indexLower + 1] };
157  return returnArray;
158  }
159  }
160  }
161 
162  if (inInterpMethod == "midpoint")
163  {
164  NdArray<double> returnArray = { (arrayCopy[indexLower] + arrayCopy[indexLower + 1]) / 2.0 };
165  return returnArray;
166  }
167 
168  THROW_INVALID_ARGUMENT_ERROR("interpolation method has not been implemented: " + inInterpMethod);
169  break; // get rid of compiler warning...
170  }
171  case Axis::COL:
172  {
173  const Shape inShape = inArray.shape();
174 
175  NdArray<double> returnArray(1, inShape.rows);
176  for (uint32 row = 0; row < inShape.rows; ++row)
177  {
178  returnArray[row] = percentile(NdArray<dtype>(&inArray.front(row), inShape.cols),
179  inPercentile, Axis::NONE, inInterpMethod).item();
180  }
181 
182  return returnArray;
183  }
184  case Axis::ROW:
185  {
186  NdArray<dtype> arrayTrans = inArray.transpose();
187  const Shape inShape = arrayTrans.shape();
188 
189  NdArray<double> returnArray(1, inShape.rows);
190  for (uint32 row = 0; row < inShape.rows; ++row)
191  {
192  returnArray[row] = percentile(NdArray<dtype>(&arrayTrans.front(row), inShape.cols, false),
193  inPercentile, Axis::NONE, inInterpMethod).item();
194  }
195 
196  return returnArray;
197  }
198  default:
199  {
200  THROW_INVALID_ARGUMENT_ERROR("Unimplemented axis type.");
201  return {}; // get rid of compiler warning
202  }
203  }
204 
205  return {}; // get rid of compiler warning
206  }
207 } // namespace nc
#define THROW_INVALID_ARGUMENT_ERROR(msg)
Definition: Error.hpp:36
#define STATIC_ASSERT_ARITHMETIC(dtype)
Definition: StaticAsserts.hpp:37
size_type size() const noexcept
Definition: NdArrayCore.hpp:4296
iterator end() noexcept
Definition: NdArrayCore.hpp:1474
Shape shape() const noexcept
Definition: NdArrayCore.hpp:4283
bool isempty() const noexcept
Definition: NdArrayCore.hpp:2843
const_reference back() const noexcept
Definition: NdArrayCore.hpp:2204
NdArray< dtype > transpose() const
Definition: NdArrayCore.hpp:4629
const_reference front() const noexcept
Definition: NdArrayCore.hpp:2772
iterator begin() noexcept
Definition: NdArrayCore.hpp:1166
value_type item() const
Definition: NdArrayCore.hpp:2931
A Shape Class for NdArrays.
Definition: Core/Shape.hpp:41
uint32 rows
Definition: Core/Shape.hpp:44
uint32 cols
Definition: Core/Shape.hpp:45
void sort(RandomIt first, RandomIt last) noexcept
Definition: StlAlgorithms.hpp:629
bool essentiallyEqual(dtype inValue1, dtype inValue2) noexcept
Definition: essentiallyEqual.hpp:52
Definition: Coordinate.hpp:45
Axis
Enum To describe an axis.
Definition: Types.hpp:46
dtype floor(dtype inValue) noexcept
Definition: floor.hpp:48
NdArray< double > percentile(const NdArray< dtype > &inArray, double inPercentile, Axis inAxis=Axis::NONE, const std::string &inInterpMethod="linear")
Definition: percentile.hpp:65
std::uint32_t uint32
Definition: Types.hpp:40