NumCpp  1.0
A C++ implementation of the Python Numpy library
percentile.hpp
Go to the documentation of this file.
1 #pragma once
30 
31 #include "NumCpp/NdArray.hpp"
32 #include "NumCpp/Core/Shape.hpp"
33 #include "NumCpp/Core/Types.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.compare("linear") != 0 &&
78  inInterpMethod.compare("lower") != 0 &&
79  inInterpMethod.compare("higher") != 0 &&
80  inInterpMethod.compare("nearest") != 0 &&
81  inInterpMethod.compare("midpoint") != 0)
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  else if (utils::essentiallyEqual(inPercentile, 100.0))
98  {
99  NdArray<dtype> returnArray = { *inArray.cend() };
100  return returnArray;
101  }
102 
103  const int32 i = static_cast<int32>(std::floor(static_cast<double>(inArray.size() - 1) * inPercentile / 100.0));
104  const uint32 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.compare("linear") == 0)
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  else if (inInterpMethod.compare("lower") == 0)
120  {
121  NdArray<dtype> returnArray = { arrayCopy[indexLower] };
122  return returnArray;
123  }
124  else if (inInterpMethod.compare("higher") == 0)
125  {
126  NdArray<dtype> returnArray = { arrayCopy[indexLower + 1] };
127  return returnArray;
128  }
129  else if (inInterpMethod.compare("nearest") == 0)
130  {
131  const double percent = inPercentile / 100.0;
132  const double percent1 = static_cast<double>(indexLower) / static_cast<double>(inArray.size() - 1);
133  const double percent2 = static_cast<double>(indexLower + 1) / static_cast<double>(inArray.size() - 1);
134  const double diff1 = percent - percent1;
135  const double diff2 = percent2 - percent;
136 
137  switch (argmin<double>({ diff1, diff2 }).item())
138  {
139  case 0:
140  {
141  NdArray<dtype> returnArray = { arrayCopy[indexLower] };
142  return returnArray;
143  }
144  case 1:
145  {
146  NdArray<dtype> returnArray = { arrayCopy[indexLower + 1] };
147  return returnArray;
148  }
149  }
150  }
151  else if (inInterpMethod.compare("midpoint") == 0)
152  {
153  NdArray<dtype> returnArray = { static_cast<dtype>((arrayCopy[indexLower] + arrayCopy[indexLower + 1]) / 2.0) };
154  return returnArray;
155  }
156  else
157  {
158  THROW_INVALID_ARGUMENT_ERROR("intperpolation method has not been implemented: " + inInterpMethod);
159  }
160 
161  // this isn't actually possible, just putting this here to get rid
162  // of the compiler warning.
163  return NdArray<dtype>(0);
164  }
165  case Axis::COL:
166  {
167  const Shape inShape = inArray.shape();
168 
169  NdArray<dtype> returnArray(1, inShape.rows);
170  for (uint32 row = 0; row < inShape.rows; ++row)
171  {
172  returnArray[row] = percentile(NdArray<dtype>(inArray.cbegin(row), inArray.cend(row)),
173  inPercentile, Axis::NONE, inInterpMethod).item();
174  }
175 
176  return returnArray;
177  }
178  case Axis::ROW:
179  {
180  NdArray<dtype> arrayTrans = inArray.transpose();
181  const Shape inShape = arrayTrans.shape();
182 
183  NdArray<dtype> returnArray(1, inShape.rows);
184  for (uint32 row = 0; row < inShape.rows; ++row)
185  {
186  returnArray[row] = percentile(NdArray<dtype>(arrayTrans.cbegin(row), arrayTrans.cend(row)),
187  inPercentile, Axis::NONE, inInterpMethod).item();
188  }
189 
190  return returnArray;
191  }
192  default:
193  {
194  // this isn't actually possible, just putting this here to get rid
195  // of the compiler warning.
196  return NdArray<dtype>(0);
197  }
198  }
199  }
200 }
StaticAsserts.hpp
nc::NdArray::item
value_type item() const
Definition: NdArrayCore.hpp:2950
nc::NdArray::shape
Shape shape() const noexcept
Definition: NdArrayCore.hpp:4296
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:4591
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:4310
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