Related
I wonder if there is a way to force sklearn NearestNeighbors algorithm, to take into account the order of a point in the input array, when there are duplicate points.
To illustrate:
>>> from sklearn.neighbors import NearestNeighbors
>>> import numpy as np
X = np.array([[-1, -1], [-2, -1], [-3, -2], [1, 1], [2, 1], [3, 2]])
nbrs = NearestNeighbors(n_neighbors=2, algorithm='ball_tree').fit(X)
distances, indices = nbrs.kneighbors(X)
indices
>>>> array([[0, 1],
[1, 0],
[2, 1],
[3, 4],
[4, 3],
[5, 4]])
Because the query set matches the training set, the nearest neighbor of each point is the point itself, at a distance of zero. If however, I allow for duplicate points in X, the algorithm, understandably, does not distinguish between the duplicates:
X = np.array([[-1, -1], [-2, -1], [-3, -2], [1, 1], [2, 1],[3, 2],[-1,-1],[-1,-1]])
nbrs = NearestNeighbors(n_neighbors=2, algorithm='auto').fit(X)
distances, indices = nbrs.kneighbors(X)
indices
>>>> array([[6, 0],
[1, 0],
[2, 1],
[3, 4],
[4, 3],
[5, 4],
[6, 0],
[6, 0]])
Ideally, I would like the last output to be something like:
>>>> array([[0, 6],
[1, 0],
[2, 1],
[3, 4],
[4, 3],
[5, 4],
[6, 0],
[7, 6]])
I think you cannot do that, since from the ref we got:
Warning: Regarding the Nearest Neighbors algorithms, if two neighbors,
neighbor k+1 and k, have identical distances but different labels, the
results will depend on the ordering of the training data.
I was studying how to list out all divisors of a number and came across this solution by Marc-Andre here. In his solution, there is one part of the code which does something like this:
array.product(*arrays_of_array) # the asterisk seems to have done sth.
I tried it in irb to try play around but I couldn't make sense of the outputs. I tried:
a=[0,1,2]
b=[3,4]
c=[[5,6],[7,8]]
I understand that array.product(other_array) is a method to list all combinations of the two arrays into one. With this knowledge, I tested out several experiments
a.product(b) => [[0, 3], [0, 4], [1, 3], [1, 4], [2, 3], [2, 4]] / 6 elements
a.product(*b) => TypeError: no implicit conversion of Fixnum into Array
a.product(c) => [[0, [5, 6]], [0, [7, 8]], [1, [5, 6]], [1, [7, 8]], [2, [5, 6]], [2, [7, 8]]] / 6 elements
a.product(*c) => [[0, 5, 7], [0, 5, 8], [0, 6, 7], [0, 6, 8], [1, 5, 7], [1, 5, 8], [1, 6, 7], [1, 6, 8], [2, 5, 7], [2, 5, 8], [2, 6, 7], [2, 6, 8]]
From observation, It seems the asterisk (*) has to be applied to a multi-dimensional array? (i.e. matrix?). Without the asterisk, the product returns 6 elements and the combinations only one level. While with the asterisk, the combination will go 1 level deeper and returns 12 elements, and combine until there is no array within the combinations. Where can I find more examples to study this behaviour of the asterisk?
Edit:
I tried to introduce one more variable
d=[[[9,0],[1,2]],[[3,4],[5,6]]]
a.product(*d) => [[0, [9, 0], [3, 4]], [0, [9, 0], [5, 6]], [0, [1, 2], [3, 4]], [0, [1, 2], [5, 6]], [1, [9, 0], [3, 4]], [1, [9, 0], [5, 6]], [1, [1, 2], [3, 4]], [1, [1, 2], [5, 6]], [2, [9, 0], [3, 4]], [2, [9, 0], [5, 6]], [2, [1, 2], [3, 4]], [2, [1, 2], [5, 6]]]
So the asterisk sign only makes it go one level deeper.
In the context of finding the list of divisors. Can anyone explain what the code exactly does?
require 'prime'
def factors_of(number)
primes, powers = number.prime_division.transpose
exponents = powers.map{|i| (0..i).to_a}
divisors = exponents.shift.product(*exponents).map do |powers|
primes.zip(powers).map{|prime, power| prime ** power}.inject(:*)
end
divisors.sort.map{|div| [div, number / div]}
end
p factors_of(4800) # => [[1, 4800], [2, 2400], ..., [4800, 1]]
*(splat) is used to expand collections.
In your example, with b = [3,4],
a.product(*b)
is equivalent to
a.product(3, 4)
which generates an error because Array#product expects an Array as argument, not two integers.
I am wondering how to get an array in Ruby with all combinations of positive and negative values based on the values in an input array. Order does not matter, but must be accommodating to input arrays of all sizes. It must be flexible so negative numbers could be in the input, even though I didn't include them in the example below.
For example:
input:
a = [1,2,3,4]
output:
b = [[1,2,3,4],[1,2,3,-4],[1,2,-3,-4],[-1,2,-3,-4]...[1,-2,3,-4],[1,-2,-3,-4],[-1,-2,-3,-4],[-1,-2,-3,4],[-1,-2,3,4],[-1,2,3,4]]
Your help is much appreciated!
You'll notice, as you iterate through the positives and negatives, that the pattern with which you apply the negativity is the same as the pattern you would use to increment bits as you count in binary. This is because each index in the array can have one of two values (positive or negative), just like each bit in a binary number can have one of two values (0 or 1). So, the easy solution is to map 0 and 1 to positive and negative. Then we can just do normal Ruby iterating, and check the bit at the element's corresponding index.
a = [1,2,3,4] # => [1, 2, 3, 4]
signed = [a, a.map(&:-#)] # => [[1, 2, 3, 4], [-1, -2, -3, -4]]
(0...2**a.size).each do |n| # => 0...16
p Array.new(a.size) { |i| signed[n[i]][i] } # => [1, 2, 3, 4], [-1, 2, 3, 4], [1, -2, 3, 4], [-1, -2, 3, 4], [1, 2, -3, 4], [-1, 2, -3, 4], [1, -2, -3, 4], [-1, -2, -3, 4], [1, 2, 3, -4], [-1, 2, 3, -4], [1, -2, 3, -4], [-1, -2, 3, -4], [1, 2, -3, -4], [-1, 2, -3, -4], [1, -2, -3, -4], [-1, -2, -3, -4]
end # => 0...16
# >> [1, 2, 3, 4]
# >> [-1, 2, 3, 4]
# >> [1, -2, 3, 4]
# >> [-1, -2, 3, 4]
# >> [1, 2, -3, 4]
# >> [-1, 2, -3, 4]
# >> [1, -2, -3, 4]
# >> [-1, -2, -3, 4]
# >> [1, 2, 3, -4]
# >> [-1, 2, 3, -4]
# >> [1, -2, 3, -4]
# >> [-1, -2, 3, -4]
# >> [1, 2, -3, -4]
# >> [-1, 2, -3, -4]
# >> [1, -2, -3, -4]
# >> [-1, -2, -3, -4]
Another way (a variant of #JoshuaCheek's answer):
a = [1,2,3,4]
n = a.size
(2**n).times.map { |i|
("%0#{n}b" % i).split('').zip(a).map { |b,e| (b=='1') ? e : -e } }
#=> [[-1, -2, -3, -4], [-1, -2, -3, 4], [-1, -2, 3, -4], [-1, -2, 3, 4],
# [-1, 2, -3, -4], [-1, 2, -3, 4], [-1, 2, 3, -4], [-1, 2, 3, 4],
# [ 1, -2, -3, -4], [ 1, -2, -3, 4], [ 1, -2, 3, -4], [ 1, -2, 3, 4],
# [ 1, 2, -3, -4], [ 1, 2, -3, 4], [ 1, 2, 3, -4], [ 1, 2, 3, 4]]
While other answers already dabbled in the Array methods, Array#repeated_permutation is what is really needed here:
[ 1, -1 ].repeated_permutation( 4 ).map { |p| [ 1, 2, 3, 4 ].zip( p ).map { |u, v| u * v } }
The below approach works - basically, we use a bit mask between binary 0000 to 1111 (or decimal 0 to 15) to decide which numbers should be negative (0 is positive, 1 is negative) - more details in the comments in the code below :
require 'pp'
result = []
# consider binary number mask from binary 0000 to 1111,
# where each digit if 0 uses the positive number, and if 1 uses the negative number
(0..15).each do |mask|
combin = [] # each combination
# Next, loop through the four place values (1,2,4,8)
(0..3).each do |pwr|
pv = 2 ** pwr # each place value
if ((mask & pv) == pv) # if the mask has the bit set at this place value,
combin << -(pwr + 1) # use the negative of the number (pwr + 1 gives 1, 2, 3, 4 nicely)
else # if mask doesn't have the bit set at this place value
combin << (pwr + 1) # use the positive value of the number
end
end
result << combin
end
pp result
# Output:
# [[1, 2, 3, 4],
# [-1, 2, 3, 4],
# [1, -2, 3, 4],
# [-1, -2, 3, 4],
# [1, 2, -3, 4],
# [-1, 2, -3, 4],
# [1, -2, -3, 4],
# [-1, -2, -3, 4],
# [1, 2, 3, -4],
# [-1, 2, 3, -4],
# [1, -2, 3, -4],
# [-1, -2, 3, -4],
# [1, 2, -3, -4],
# [-1, 2, -3, -4],
# [1, -2, -3, -4],
# [-1, -2, -3, -4]]
array=[]
[1,-1].each do |a|
[2,-2].each do |b|
[3,-3].each do |c|
[4,-4].each do |d|
array<<[a,b,c,d]
end
end
end
end
I'll elaborate on a more complete amswer as soon as I get my hands on a keyboard
Update:
A lot of good answer, here is the recursive way:
#input = [1,2,3,4] # or whatever
#output = []
def pos_neg(ind,in_array)
a=#input[ind]
[a,-a].each do |b|
arr=in_array.dup
arr[ind]=b
if #input.size > ind+1
pos_neg(ind+1,arr)
else
#output << arr
end
end
end
Then, you run:
pos_neg(0,[])
#output
[[1, 2, 3, 4],
[1, 2, 3, -4],
[1, 2, -3, 4],
[1, 2, -3, -4],
[1, -2, 3, 4],
[1, -2, 3, -4],
[1, -2, -3, 4],
[1, -2, -3, -4],
[-1, 2, 3, 4],
[-1, 2, 3, -4],
[-1, 2, -3, 4],
[-1, 2, -3, -4],
[-1, -2, 3, 4],
[-1, -2, 3, -4],
[-1, -2, -3, 4],
[-1, -2, -3, -4]]
Well, Ruby conveniently includes a combination method on the Array object, but first you need to create the opposite values for the numbers in the original array:
a = [1,2,3,4]
b = a.map(&:-#)
Then you'd want to concatenate the two arrays into a single array:
c = a + b
And finally you can call the combination method of the array that contains all the positive and negative values:
c.combination(4).to_a # => [[1,2,3,4], [1,2,3,-1], ...]
Here is the documentation for the combination method.
Update: I like what Boris Stitnicky came up with. Here's a variation on that:
a = [1,2,3,4]
def sign_permutations(arr)
[1, -1].repeated_permutation(arr.length).map do |signs|
signs.map.with_index do |sign, index|
arr[index] * sign
end
end
end
puts sign_permutations(a).inspect
I'm new to coding and new to Ruby. I'm working on this problem in my spare time since I am new to ruby and am having a difficult time getting my code to iterate through every created subset.
Here is my code:
#Given a set of integers, and a value sum, i.e. value sum of 0
#determine if there is a subset of the given set with sum equal to given sum.
class Array
def SubSetSumtoZero
if self.collect{|sum,x| sum + x == 0}
detected = self.select {|sum,x| sum + x == 0}
puts "\r\n #{detected} Sums to Zero \r\n"
else self.collect{|sum,x| sum + x -= 0}
notdetected = self.select {|sum, x| sum + x -= 0}
puts "\r\n#{notdetected} Does not sum to Zero\r\n"
end
end
end
originalSet = [-9, -7, -2, 2, 7, 9]
arr = []
for i in 2..(originalSet.length) do
arr = arr + originalSet.combination(i).to_a
arr.SubSetSumtoZero
end
And here are my results:
[[-9, 9], [-7, 7], [-2, 2]] Sums to Zero
[[-9, 9], [-7, 7], [-2, 2], [-7, 7, 9], [-2, 2, 7], [-2, 2, 9]] Sums to Zero
[[-9, 9], [-7, 7], [-2, 2], [-7, 7, 9], [-2, 2, 7], [-2, 2, 9], [-2, 2, 7, 9]] Sums to Zero
[[-9, 9], [-7, 7], [-2, 2], [-7, 7, 9], [-2, 2, 7], [-2, 2, 9], [-2, 2, 7, 9]] Sums to Zero
[[-9, 9], [-7, 7], [-2, 2], [-7, 7, 9], [-2, 2, 7], [-2, 2, 9], [-2, 2, 7, 9]] Sums to Zero
[Finished in 0.1s]
I know that at some point the entire array will sum up to zero. Any ideas why this is happening?
I know you specifically asked for a recursive solution, but since #hjing has provided one, I would like to show you how your question can be answered in a more compact and straightforward way by using powerful, built-in methods from Ruby's Enumerable module and Array class.
Code
def find_it(array, tot)
(1..array.size).each_with_object([]) { |n,arr|
array.combination(n).each { |a| arr << a if a.reduce(:+) == tot } }
end
Example
find_it([-9, -7, -2, 2, 7, 9], 0) #=> [-9, 9]
#=> [[-9, 9], [-7, 7], [-2, 2],
# [-9, 2, 7], [-7, -2, 9],
# [-9, -7, 7, 9], [-9, -2, 2, 9], [-7, -2, 2, 7],
# [-9, -7, -2, 2, 7, 9]]
Explanation
array = [-9, -7, -2, 2, 7, 9]
tot = 0
r = 1..array.size #=> 1..6 (Range object)
Each value of this range is size of subsets that will be considered. We will first examine subsets of size 1, then subsets of size 2, and so on, up to subsets of size 6, of which there is but one (array).
enum1 = r.each_with_object([]) # => #<Enumerator: 1..6:each_with_object([])>
To see the values that the enumerator enum1 will pass to its block, we can convert it to an array:
enum1.to_a #=> [[1, []], [2, []], [3, []], [4, []], [5, []], [6, []]]
Enumerable#each_with_object creates an initially empty array that is represented by the block variable arr. That first value enum passes to its block is the array [0, []], causing the block variables to be assigned as follows:
n => 1
arr => []
enum2 = array.combination(n) #=> array.combination(1)
#=> #<Enumerator: [-9, -7, -2, 2, 7, 9]:combination(1)>
Here Array#combination generates all combinations of one element from array. enum2 will therefore pass the following elements to its block:
enum2.to_a
#=> [[-9], [-7], [-2], [2], [7], [9]]
The first element enum2 passes to its block is [-9], causing the bloc block variable to be assigned as follows:
a => [-9]
so the block expression becomes:
arr << a if a.reduce(:+) == tot #=> arr << [-9] if [-9].reduce(:+) == 0
Enumerable#reduce (aka, inject) with argument :+ (the addition method) merely sums the elements of its receiver, [-9], which obviously is -9. As -9 != 0, [-9] is not appended to arr. Clearly, the only array containing a single element that sums to zero is [0], but that array is not present in this example. Therefore, arr remains empty after enum2 has enumerated all its elements.
enum1 now passes the element [2, []] to its block, setting the block variables to:
n => 2
arr => []
resulting in:
enum2 = array.combination(n) #=> array.combination(2)
#=> #<Enumerator: [-9, -7, -2, 2, 7, 9]:combination(2)>
enum2.to_a
#=> [[-9, -7], [-9, -2], [-9, 2], [-9, 7], [-9, 9], [-7, -2], [-7, 2],
# [-7, 7], [-7, 9], [-2, 2], [-2, 7], [-2, 9], [ 2, 7], [ 2, 9], [7, 9]]
We find that elements [-9, 9], [-7, 7] and [-2, 2] each sum to zero, so arr becomes:
arr => [[-9, 9], [-7, 7] and [-2, 2]]
after all combinations of two elements have been enumerated. Next combinations of three are considered, and so on.
A straightforward recursive solution would be to write a function that computes the powerset of an array. Afterwards, select all elements in the powerset that fulfills your desired predicate.
An example implementation:
def powerset(array)
if array.empty?
[[]]
else
first_elem, *rest_elems = array
subsets = []
powerset(rest_elems).each do |subset|
subsets.push(subset)
subsets.push(subset.clone.push(first_elem))
end
subsets
end
end
def sums_to_zero?(array)
array.reduce(0, :+) == 0
end
def subsets_that_sum_to_zero(array)
powerset(array).select { |subset| sums_to_zero?(subset) }
end
original_set = [-9, -7, -2, 2, 7, 9]
subsets_that_sum_to_zero(original_set).each do |subset|
puts "The subset #{subset} sums to zero!"
end
# The subset [] sums to zero!
# The subset [2, -2] sums to zero!
# The subset [7, -7] sums to zero!
# The subset [7, 2, -9] sums to zero!
# The subset [7, 2, -2, -7] sums to zero!
# The subset [9, -9] sums to zero!
# The subset [9, -2, -7] sums to zero!
# The subset [9, 2, -2, -9] sums to zero!
# The subset [9, 7, -7, -9] sums to zero!
# The subset [9, 7, 2, -2, -7, -9] sums to zero!
See wikipedia for an explanation of the powerset algorithm.
Here is a straight forward recursive solution for zero sum:
def find_subsets(arr)
return arr if arr.empty?
result = (0...arr.length).flat_map do |i|
find_subsets(arr[0...i] + arr[i+1..-1])
end
result << arr if arr.inject(:+) == 0
result.uniq
end
It collects all the results from dropping a single element from the array (this is the recursion), and adds to it the array itself, if it fits the requirement (sums to zero).
It is not the most efficient solution since it may repeat the calculation for subarrays coming from several paths (that it why the last line uniqs the result) - but it is the easiest implementation.
I have an Array of pairs of Vectors that are all edges in a clockwise path around a polygon. The problem is, they're not in the right order. I would like to sort them so that the start and end of the Array are the same Vector, and each individual point overlaps (endpoint-to-startpoint):
require 'matrix'
unsorted_points = [[Vector[-5, 0], Vector[-3, 2]],
[Vector[-3, 2], Vector[3, 2]],
[Vector[-3, -2], Vector[-5, 0]],
[Vector[3, 2], Vector[5, 0]],
[Vector[3, -2], Vector[-3, -2]],
[Vector[5, 0], Vector[3, -2]]]
sorted_points = [[Vector[-5, 0], Vector[-3, 2]],
[Vector[-3, 2], Vector[3, 2]],
[Vector[3, 2], Vector[5, 0]],
[Vector[5, 0], Vector[3, -2]],
[Vector[3, -2], Vector[-3, -2]],
[Vector[-3, -2], Vector[-5, 0]]]
What's the most Ruby-idiomatic way to do this?
edit: Vectors are objects from the 'matrix' library, but they can be indexed just like arrays, e.g. unsorted_points[0][0][0] is -5.
First turn the original point pair array into a map with the first point the key, and the second the value:
ptsMap = Hash[ * unsorted_points.flatten(1) ]
=> {Vector[-5, 0] => Vector[-3, 2],
Vector[-3, 2] => Vector[3, 2],
Vector[-3, -2] => Vector[-5, 0],
Vector[3, 2] => Vector[5, 0],
Vector[3, -2] => Vector[-3, -2],
Vector[5, 0] => Vector[3, -2] }
Then start with the first point pair and chain from second point to the first via the map (I'd note your array doesn't contain "points" it contains edges between two points):
ordered_edges = (1...unsorted_points.size).inject ( [unsorted_points.first] ) do |acc,_|
nextPt = acc.last[1]
acc << [ nextPt, ptsMap[nextPt] ]
end
=> [[Vector[-5, 0], Vector[-3, 2]],
[Vector[-3, 2], Vector[3, 2]],
[Vector[3, 2], Vector[5, 0]],
[Vector[5, 0], Vector[3, -2]],
[Vector[3, -2], Vector[-3, -2]],
[Vector[-3, -2], Vector[-5, 0]] ]
Note that points are not strictly comparable in this context, so there is no total ordering (as required for a simple sort. Each of your point pairs describes an edge which supplies a partial ordering. The above finds a candidate total ordering assuming the first edge's head is the first point you want.
This technique will fail if the original list doesn't actually describe a set of discrete connected points. You might get more robust results using topological sorting. Ruby has a library for this: TSort. With this you could detect when your original set of edges are not a single strongly connected component.
[Edit: I originally presented two ways of doing it, one using sort, the other recursion. #dbenhur showed that no sort would work because there was not a complete ordering of the elements of the array. I've therefore deleted that approach. For the record, the heart of my misguided sort was:
unsorted.sort {|v1,v2| (v1 == first || v1[1]==v2[0]) ? -1 : 1}
The second approach was the use of recursion. Upon reflection, it way obvious I could do the same thing in a simple loop, which follows.]
sorted = [unsorted_points.shift]
until unsorted_points.empty?
node = sorted[-1][1]
target = unsorted_points.find {|e| e[0] == node}
sorted << unsorted_points.delete(target)
end
sorted
# => [[Vector[-5, 0], Vector[-3, 2]],
[Vector[-3, 2], Vector[ 3, 2]],
[Vector[ 3, 2], Vector[ 5, 0]],
[Vector[ 5, 0], Vector[ 3, -2]],
[Vector[ 3, -2], Vector[-3, -2]],
[Vector[-3, -2], Vector[-5, 0]]]