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