def gradient_descent(alpha=0.01, num_iters=1500)
      m = @xs.length
      alpha_m = (alpha / m)

      (num_iters).times do

        @thetas = 
          @xs.map do |x_row|
            x_row.zip(@thetas).map do |x, theta|
             x * theta
            end.inject(:+)
          end.zip(@ys).map do |(predict_val, y)|  
            predict_val - y 
          end.zip(@xs).map do |(y, x_row)|
            x_row.map { |x| x * y }
          end.reduce([0.0] * 2) do |sum, val|
            sum.zip(val).map { |(a, b)| a + b}
          end.map do |value|
            alpha_m * value
          end.zip( @thetas ).map do |(a, b)|
            b - a
          end
      end

      @thetas
    end
def gradient_descent(alpha=0.01, num_iters=1500)
      m = @xs.length
      alpha_m = (alpha / m)

      (num_iters).times do

        @thetas = 
          @xs.map do |x_row|
            x_row.zip(@thetas).map do |x, theta|
             x * theta
            end.inject(:+)
          end.zip(@ys).map do |(predict_val, y)|  
            predict_val - y 
          end.zip(@xs).map do |(y, x_row)|
            x_row.map { |x| x * y }
          end.reduce([0.0] * 2) do |sum, val|
            sum.zip(val).map { |(a, b)| a + b}
          end.map do |value|
            alpha_m * value
          end.zip( @thetas ).map do |(a, b)|
            b - a
          end
      end

      @thetas
    end
thetas - (alpha/m) * [X' * ( X*thetas - y )]