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