| 233 | |
| 234 | |
| 235 | static void CalcQuantizationAndNanMode( |
| 236 | const TFloatValuesHolder& srcFeature, |
| 237 | const TSubsetIndexingForBuildBorders& subsetIndexingForBuildBorders, |
| 238 | const TQuantizedFeaturesInfo& quantizedFeaturesInfo, |
| 239 | const TMaybe<TVector<float>>& initialBorders, |
| 240 | TMaybe<float> quantizedDefaultBinFraction, |
| 241 | ENanMode* nanMode, |
| 242 | NSplitSelection::TQuantization* quantization |
| 243 | ) { |
| 244 | const auto& binarizationOptions = quantizedFeaturesInfo.GetFloatFeatureBinarization(srcFeature.GetId()); |
| 245 | |
| 246 | CB_ENSURE(binarizationOptions.BorderCount > 0, "Border count should be non-negative"); |
| 247 | |
| 248 | const ui32 sampleCount = subsetIndexingForBuildBorders.ComposedSubset.Size(); |
| 249 | |
| 250 | // featureValues.Values will not contain nans |
| 251 | NSplitSelection::TFeatureValues featureValues{TVector<float>()}; |
| 252 | |
| 253 | bool hasNans = false; |
| 254 | |
| 255 | auto processNonDefaultValue = [&] (ui32 /*idx*/, float value) { |
| 256 | if (std::isnan(value)) { |
| 257 | hasNans = true; |
| 258 | } else { |
| 259 | featureValues.Values.push_back(value); |
| 260 | } |
| 261 | }; |
| 262 | |
| 263 | if (const auto* denseSrcFeature = dynamic_cast<const TFloatArrayValuesHolder*>(&srcFeature)) { |
| 264 | ITypedArraySubsetPtr<float> srcFeatureData = denseSrcFeature->GetData(); |
| 265 | |
| 266 | ITypedArraySubsetPtr<float> srcDataForBuildBorders = srcFeatureData->CloneWithNewSubsetIndexing( |
| 267 | &subsetIndexingForBuildBorders.ComposedSubset |
| 268 | ); |
| 269 | |
| 270 | // does not contain nans |
| 271 | featureValues.Values.reserve(sampleCount); |
| 272 | |
| 273 | srcDataForBuildBorders->ForEach(processNonDefaultValue); |
| 274 | } else if (const auto* sparseSrcFeature = dynamic_cast<const TFloatSparseValuesHolder*>(&srcFeature)) { |
| 275 | const TConstPolymorphicValuesSparseArray<float, ui32>& sparseData = sparseSrcFeature->GetData(); |
| 276 | |
| 277 | ui32 nonDefaultValuesInSampleCount = 0; |
| 278 | |
| 279 | if (const auto* invertedIndexedSubset |
| 280 | = std::get_if<TInvertedIndexedSubset<ui32>>(&*subsetIndexingForBuildBorders.InvertedSubset)) |
| 281 | { |
| 282 | TConstArrayRef<ui32> invertedMapping = invertedIndexedSubset->GetMapping(); |
| 283 | sparseData.ForEachNonDefault( |
| 284 | [&, invertedMapping] (ui32 idx, float value) { |
| 285 | if (invertedMapping[idx] != TInvertedIndexedSubset<ui32>::NOT_PRESENT) { |
| 286 | processNonDefaultValue(idx, value); |
| 287 | ++nonDefaultValuesInSampleCount; |
| 288 | } |
| 289 | } |
| 290 | ); |
| 291 | } else { // TFullSubset |
| 292 | sparseData.ForEachNonDefault( |
no test coverage detected