NumCpp  2.4.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:
65  template<typename dtype>
66  NdArray<dtype> 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 (inInterpMethod != "linear" &&
77  inInterpMethod != "lower" &&
78  inInterpMethod != "higher" &&
79  inInterpMethod != "nearest" &&
80  inInterpMethod != "midpoint")
81  {
82  std::string errStr = "input interpolation method is not a vaid option.\n";
83  errStr += "\tValid options are 'linear', 'lower', 'higher', 'nearest', 'midpoint'.";
85  }
86 
87  switch (inAxis)
88  {
89  case Axis::NONE:
90  {
91  if (utils::essentiallyEqual(inPercentile, 0.0))
92  {
93  NdArray<dtype> returnArray = { *inArray.cbegin() };
94  return returnArray;
95  }
96  if (utils::essentiallyEqual(inPercentile, 100.0))
97  {
98  NdArray<dtype> returnArray = { *inArray.cend() };
99  return returnArray;
100  }
101 
102  const auto i = static_cast<int32>(std::floor(static_cast<double>(inArray.size() - 1) * inPercentile / 100.0));
103  const auto indexLower = static_cast<uint32>(clip<uint32>(i, 0, inArray.size() - 2));
104 
105  NdArray<double> arrayCopy = inArray.template astype<double>();
106  stl_algorithms::sort(arrayCopy.begin(), arrayCopy.end());
107 
108  if (inInterpMethod == "linear")
109  {
110  const double percentI = static_cast<double>(indexLower) / static_cast<double>(inArray.size() - 1);
111  const double fraction = (inPercentile / 100.0 - percentI) /
112  (static_cast<double>(indexLower + 1) / static_cast<double>(inArray.size() - 1) - percentI);
113 
114  const double returnValue = arrayCopy[indexLower] + (arrayCopy[indexLower + 1] - arrayCopy[indexLower]) * fraction;
115  NdArray<dtype> returnArray = { returnValue };
116  return returnArray;
117  }
118 
119  if (inInterpMethod == "lower")
120  {
121  NdArray<dtype> returnArray = { arrayCopy[indexLower] };
122  return returnArray;
123  }
124 
125  if (inInterpMethod == "higher")
126  {
127  NdArray<dtype> returnArray = { arrayCopy[indexLower + 1] };
128  return returnArray;
129  }
130 
131  if (inInterpMethod == "nearest")
132  {
133  const double percent = inPercentile / 100.0;
134  const double percent1 = static_cast<double>(indexLower) / static_cast<double>(inArray.size() - 1);
135  const double percent2 = static_cast<double>(indexLower + 1) / static_cast<double>(inArray.size() - 1);
136  const double diff1 = percent - percent1;
137  const double diff2 = percent2 - percent;
138 
139  switch (argmin<double>({ diff1, diff2 }).item())
140  {
141  case 0:
142  {
143  NdArray<dtype> returnArray = { arrayCopy[indexLower] };
144  return returnArray;
145  }
146  case 1:
147  {
148  NdArray<dtype> returnArray = { arrayCopy[indexLower + 1] };
149  return returnArray;
150  }
151  }
152  }
153 
154  if (inInterpMethod == "midpoint")
155  {
156  NdArray<dtype> returnArray = { static_cast<dtype>((arrayCopy[indexLower] + arrayCopy[indexLower + 1]) / 2.0) };
157  return returnArray;
158  }
159 
160  THROW_INVALID_ARGUMENT_ERROR("intperpolation method has not been implemented: " + inInterpMethod);
161  break; // get rid of compiler warning...
162  }
163  case Axis::COL:
164  {
165  const Shape inShape = inArray.shape();
166 
167  NdArray<dtype> returnArray(1, inShape.rows);
168  for (uint32 row = 0; row < inShape.rows; ++row)
169  {
170  returnArray[row] = percentile(NdArray<dtype>(inArray.cbegin(row), inArray.cend(row)),
171  inPercentile, Axis::NONE, inInterpMethod).item();
172  }
173 
174  return returnArray;
175  }
176  case Axis::ROW:
177  {
178  NdArray<dtype> arrayTrans = inArray.transpose();
179  const Shape inShape = arrayTrans.shape();
180 
181  NdArray<dtype> returnArray(1, inShape.rows);
182  for (uint32 row = 0; row < inShape.rows; ++row)
183  {
184  returnArray[row] = percentile(NdArray<dtype>(arrayTrans.cbegin(row), arrayTrans.cend(row)),
185  inPercentile, Axis::NONE, inInterpMethod).item();
186  }
187 
188  return returnArray;
189  }
190  default:
191  {
192  THROW_INVALID_ARGUMENT_ERROR("Unimplemented axis type.");
193  return {}; // get rid of compiler warning
194  }
195  }
196 
197  return NdArray<dtype>(0);
198  }
199 } // 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
STATIC_ASSERT_ARITHMETIC
#define STATIC_ASSERT_ARITHMETIC(dtype)
Definition: StaticAsserts.hpp:37
nc::Axis::ROW
@ ROW
argmin.hpp
nc::percentile
NdArray< dtype > percentile(const NdArray< dtype > &inArray, double inPercentile, Axis inAxis=Axis::NONE, const std::string &inInterpMethod="linear")
Definition: percentile.hpp:66
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
nc::NdArray::end
iterator end() noexcept
Definition: NdArrayCore.hpp:1431
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
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::NdArray::begin
iterator begin() noexcept
Definition: NdArrayCore.hpp:1087
nc::Axis::COL
@ COL