NumCpp  2.6.2
A Templatized Header Only C++ Implementation of the Python NumPy Library
percentile.hpp
Go to the documentation of this file.
1 
28 #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:
65  template<typename dtype>
66  NdArray<double> percentile(const NdArray<dtype>& inArray, double inPercentile,
67  Axis inAxis = Axis::NONE, const std::string& inInterpMethod = "linear")
68  {
70 
71  if (inPercentile < 0.0 || inPercentile > 100.0)
72  {
73  THROW_INVALID_ARGUMENT_ERROR("input percentile value must be of the range [0, 100].");
74  }
75 
76  if (inArray.isempty())
77  {
78  return {};
79  }
80  else if (inArray.size() == 1)
81  {
82  NdArray<double> returnArray = { static_cast<double>(inArray.front()) };
83  return returnArray;
84  }
85 
86  if (inInterpMethod != "linear" &&
87  inInterpMethod != "lower" &&
88  inInterpMethod != "higher" &&
89  inInterpMethod != "nearest" &&
90  inInterpMethod != "midpoint")
91  {
92  std::string errStr = "input interpolation method is not a vaid option.\n";
93  errStr += "\tValid options are 'linear', 'lower', 'higher', 'nearest', 'midpoint'.";
95  }
96 
97  switch (inAxis)
98  {
99  case Axis::NONE:
100  {
101  NdArray<double> arrayCopy = inArray.template astype<double>();
102  stl_algorithms::sort(arrayCopy.begin(), arrayCopy.end());
103 
104  if (utils::essentiallyEqual(inPercentile, 0.0))
105  {
106  NdArray<double> returnArray = { arrayCopy.front() };
107  return returnArray;
108  }
109  if (utils::essentiallyEqual(inPercentile, 100.0))
110  {
111  NdArray<double> returnArray = { arrayCopy.back() };
112  return returnArray;
113  }
114 
115  const auto i = static_cast<uint32>(std::floor(static_cast<double>(inArray.size() - 1) * inPercentile / 100.0));
116  const auto indexLower = clip<uint32>(i, 0, inArray.size() - 2);
117 
118  if (inInterpMethod == "linear")
119  {
120  const double percentI = static_cast<double>(indexLower) / static_cast<double>(inArray.size() - 1);
121  const double fraction = (inPercentile / 100.0 - percentI) /
122  (static_cast<double>(indexLower + 1) / static_cast<double>(inArray.size() - 1) - percentI);
123 
124  NdArray<double> returnArray = { arrayCopy[indexLower] + (arrayCopy[indexLower + 1] - arrayCopy[indexLower]) * fraction };
125  return returnArray;
126  }
127 
128  if (inInterpMethod == "lower")
129  {
130  NdArray<double> returnArray = { arrayCopy[indexLower] };
131  return returnArray;
132  }
133 
134  if (inInterpMethod == "higher")
135  {
136  NdArray<double> returnArray = { arrayCopy[indexLower + 1] };
137  return returnArray;
138  }
139 
140  if (inInterpMethod == "nearest")
141  {
142  const double percent = inPercentile / 100.0;
143  const double percent1 = static_cast<double>(indexLower) / static_cast<double>(inArray.size() - 1);
144  const double percent2 = static_cast<double>(indexLower + 1) / static_cast<double>(inArray.size() - 1);
145  const double diff1 = percent - percent1;
146  const double diff2 = percent2 - percent;
147 
148  switch (argmin<double>({ diff1, diff2 }).item())
149  {
150  case 0:
151  {
152  NdArray<double> returnArray = { arrayCopy[indexLower] };
153  return returnArray;
154  }
155  case 1:
156  {
157  NdArray<double> returnArray = { arrayCopy[indexLower + 1] };
158  return returnArray;
159  }
160  }
161  }
162 
163  if (inInterpMethod == "midpoint")
164  {
165  NdArray<double> returnArray = { (arrayCopy[indexLower] + arrayCopy[indexLower + 1]) / 2.0 };
166  return returnArray;
167  }
168 
169  THROW_INVALID_ARGUMENT_ERROR("interpolation method has not been implemented: " + inInterpMethod);
170  break; // get rid of compiler warning...
171  }
172  case Axis::COL:
173  {
174  const Shape inShape = inArray.shape();
175 
176  NdArray<double> returnArray(1, inShape.rows);
177  for (uint32 row = 0; row < inShape.rows; ++row)
178  {
179  returnArray[row] = percentile(NdArray<dtype>(&inArray.front(row), inShape.cols),
180  inPercentile, Axis::NONE, inInterpMethod).item();
181  }
182 
183  return returnArray;
184  }
185  case Axis::ROW:
186  {
187  NdArray<dtype> arrayTrans = inArray.transpose();
188  const Shape inShape = arrayTrans.shape();
189 
190  NdArray<double> returnArray(1, inShape.rows);
191  for (uint32 row = 0; row < inShape.rows; ++row)
192  {
193  returnArray[row] = percentile(NdArray<dtype>(&arrayTrans.front(row), inShape.cols, false),
194  inPercentile, Axis::NONE, inInterpMethod).item();
195  }
196 
197  return returnArray;
198  }
199  default:
200  {
201  THROW_INVALID_ARGUMENT_ERROR("Unimplemented axis type.");
202  return {}; // get rid of compiler warning
203  }
204  }
205 
206  return {}; // get rid of compiler warning
207  }
208 } // namespace nc
#define THROW_INVALID_ARGUMENT_ERROR(msg)
Definition: Error.hpp:36
#define STATIC_ASSERT_ARITHMETIC(dtype)
Definition: StaticAsserts.hpp:37
Holds 1D and 2D arrays, the main work horse of the NumCpp library.
Definition: NdArrayCore.hpp:72
size_type size() const noexcept
Definition: NdArrayCore.hpp:4497
iterator end() noexcept
Definition: NdArrayCore.hpp:1558
Shape shape() const noexcept
Definition: NdArrayCore.hpp:4483
bool isempty() const noexcept
Definition: NdArrayCore.hpp:3012
const_reference back() const noexcept
Definition: NdArrayCore.hpp:2344
NdArray< dtype > transpose() const
Definition: NdArrayCore.hpp:4841
const_reference front() const noexcept
Definition: NdArrayCore.hpp:2933
iterator begin() noexcept
Definition: NdArrayCore.hpp:1214
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:66
std::uint32_t uint32
Definition: Types.hpp:40