Ejemplo n.º 1
0
        /// <summary>
        /// This converts the value into a normalized vector (values from -1 to 1 in each dimension)
        /// </summary>
        /// <remarks>
        /// This is useful if you want to convert numbers into vectors
        ///
        /// Say you want to do a SOM against a database.  Each column needs to be mapped to a vector.  Then all vectors of a row will get
        /// stitched together to be one intance of ISOMInput.Weights
        ///
        /// If one of the columns is numeric (maybe dollars or quantities), then you would use this method
        ///
        /// The first step would be to prequery so see what the range of possible values are.  Run that maximum expected value through
        /// GetConvertBaseProps() to figure out what base to represent the numbers as.  This method converts the number to that base,
        /// then normalizes each digit to -1 to 1 (sort of like percent of base)
        /// </remarks>
        private static double[] ConvertToVector_Direct(double value, SOMConvertToVectorProps props)
        {
            // Convert to a different base
            long scaledValue = Convert.ToInt64(value * props.Number_ScaleToLong);

            int[] converted = MathND.ConvertToBase(scaledValue, props.Number_BaseConvertTo.Value);

            // Too big, return 1s
            if (converted.Length > props.Width)
            {
                double maxValue = value < 0 ? -1d : 1d;
                return(Enumerable.Range(0, props.Width).Select(o => maxValue).ToArray());
            }

            // Normalize (treat each item like a percent)
            double baseDbl = props.Number_BaseConvertTo.Value.ToDouble();

            double[] normalized = converted.
                                  Select(o => o.ToDouble() / baseDbl).
                                  ToArray();

            // Return, make sure the array is the right size
            if (normalized.Length < props.Width)
            {
                return(Enumerable.Range(0, props.Width - normalized.Length).
                       Select(o => 0d).
                       Concat(normalized).
                       ToArray());
            }
            else
            {
                return(normalized);
            }
        }
Ejemplo n.º 2
0
        /// <summary>
        /// This washes the bits to the right with values approaching one
        /// </summary>
        /// <remarks>
        /// The leftmost bit is most significant, and needs to be returned acurately.  The bits to the right don't matter as much, but
        /// the self organizing map just groups things together based on the pattern of the bits.  So the bits to the right need to approach
        /// one (think of them as overidden by the bits to the left)
        ///
        /// I didn't want linear, I wanted something faster.  So the bits to the right follow a sqrt curve (x axis scaled between 0 and 1
        /// over the remaining bits)
        ///
        /// Example:
        ///     If this trend toward one isn't there, then these two values would map close to each other (even though the first one represents
        ///     1, and the second could represent 201)
        ///         0 0 0 0 1
        ///         0 .1 0 0 1
        ///     This method would turn these into something like:
        ///         0 0 0 0 1
        ///         0 .1 .6 .95 1       --- bits to the right follow a sqrt toward 1
        ///
        /// Instead of sqrt, it's actually between x^POWMIN and x^POWMAX.  The value of the bit becomes a percent from min to max
        /// </remarks>
        private static double[] ConvertToVector_LeftSignificant(double value, SOMConvertToVectorProps props)
        {
            const double POWMIN = .1;
            const double POWMAX = .04;

            // Convert to a different base
            long scaledValue = Convert.ToInt64(value * props.Number_ScaleToLong);

            int[] converted = MathND.ConvertToBase(scaledValue, props.Number_BaseConvertTo.Value);

            if (converted.Length == 0)
            {
                // Zero, return 0s
                return(Enumerable.Range(0, props.Width).Select(o => 0d).ToArray());
            }
            else if (converted.Length > props.Width)
            {
                // Too big, return 1s
                double maxValue = value < 0 ? -1d : 1d;
                return(Enumerable.Range(0, props.Width).Select(o => maxValue).ToArray());
            }

            // Normalize so it's between -1 and 1
            double[] normalized = new double[converted.Length];

            double baseDbl = props.Number_BaseConvertTo.Value.ToDouble();

            // Leftmost bit
            normalized[0] = converted[0].ToDouble() / baseDbl;
            double absFirst = Math.Abs(normalized[0]);

            // Bits to the right of the leftmost (their values are made to approach 1)
            if (converted.Length > 1)
            {
                // The sqrt will be between 0 and 1, so scale the x and y
                double yGap   = 1d - absFirst;
                double xScale = 1d / (normalized.Length - 1);

                for (int cntr = 1; cntr < normalized.Length; cntr++)
                {
                    // Y will be between these two curves
                    double yMin = Math.Pow(cntr * xScale, POWMIN);
                    double yMax = Math.Pow(cntr * xScale, POWMAX);

                    // Treat this bit like a percent between the two curves
                    double y = UtilityCore.GetScaledValue(yMin, yMax, 0, props.Number_BaseConvertTo.Value, Math.Abs(converted[cntr]));

                    y *= yGap;
                    y += absFirst;

                    if (normalized[0] < 0)
                    {
                        y = -y;
                    }

                    normalized[cntr] = y;
                }
            }

            // Return, make sure the array is the right size
            if (normalized.Length < props.Width)
            {
                return(Enumerable.Range(0, props.Width - normalized.Length).
                       Select(o => 0d).
                       Concat(normalized).
                       ToArray());
            }
            else
            {
                return(normalized);
            }
        }