Organise array as based on dates field - ruby-on-rails

I am working on a rails app with vue in front end.
I have the following data as below
records = [["2020-07-01", "Jamie", 66],
["2020-07-01", "Rob", 12],
["2020-08-01", "Jamie", 31],
["2020-09-01", "Jamie", 46],
["2020-09-01", "Rob", 10],
["2020-10-01", "Rob", 4]]
I want to organise this data as
final_result = [{:name=>"Jamie", :data=>[66, 31, 46, 0]},
{:name=>"Rob", :data=>[12, 0, 10, 4]}]
I was thinking of using .map something like records.map but I am not able to figure-out how can I combine the values in the data field
like in the final_result I have combined the values 66, 31, 46, 0 for Jamie and 12, 0, 10, 4 for Rob based on the dates: July, August, September, October.
If the value is not present in any month then it is set to 0. Please help me resolve this issue.
Update 1
Answer not working for this data set below
records = [
["2020-01-01", nil, nil, 0],
["2020-02-01", nil, nil, 0],
["2020-03-01", nil, nil, 0],
["2020-04-01", nil, nil, 0],
["2020-05-01", nil, nil, 0],
["2020-06-01", nil, nil, 0],
["2020-07-01", 2, "Jamie", 66],
["2020-07-01", 7, "Rob", 1],
["2020-08-01", 2, "Jamie", 29],
["2020-08-01", 7, "Rob", 2]]
in the case about the output should be
[{:name=>"Jamie", :data=>[0, 0, 0, 0, 0, 0, 66, 29]},
{:name=>"Rob", :data=>[0, 0, 0, 0, 0, 0, 1, 2]}]
But according to Answer
the output is
[{:name=>"Jamie", :data=>[0, 0, 0, 0, nil, nil, 66, 29]},
{:name=>"Rob", :data=>[0, 0, 0, 0, nil, nil, 1, 2]}]
I am not able to figure out why is it showing nil values instead of zero.

records = [["2020-07-01", "Jamie", 66],
["2020-07-01", "Rob", 12],
["2020-08-01", "Jamie", 31],
["2020-09-01", "Jamie", 46],
["2020-09-01", "Rob", 10],
["2020-10-01", "Rob", 4]]
months = records.map { |record| Date.parse(record.first, '').month }.uniq.sort
result = []
result_hash = records.inject({}) do |memo, record|
memo[record.second] ||= Array.new(4).map { |_| 0 }
memo[record.second][Date.parse(record.first).month - months.first] = record.last
memo
end
result_hash.each { |key, value| result << { name: key, data: value }}
p result
=>
[{:name=>"Jamie", :data=>[66, 31, 46, 0]}, {:name=>"Rob", :data=>[12, 0, 10, 4]}]

Related

How to predict Total Hours needed with List as Input?

I am struggling with the problem I am facing:
I have a dataset of different products (Cars) that have certain Work Orders open at a given time. I know from historical data how much time this work in TOTAL has caused.
Now I want to predict it for another Car (e.g. Car 3).
Which type of algorithm, regression shall I use for this?
My idea was to transform this row based dataset into column based with binary values e.g. Brake: 0/1, Screen 0/1.. But then I will have lots of Inputs as the number of possible Inputs is 100-200..
Here's a quick idea using multi-factor regression for 30 jobs, each of which is some random accumulation of 6 tasks with a "true cost" for each task. We can regress against the task selections in each job to estimate the cost coefficients that best explain the total job costs.
First done w/ no "noise" in the system (tasks are exact), then with some random noise.
A "more thorough" job would include examining the R-squared value and plotting the residuals to ensure linearity.
In [1]: from sklearn import linear_model
In [2]: import numpy as np
In [3]: jobs = np.random.binomial(1, 0.6, (30, 6))
In [4]: true_costs = np.array([10, 20, 5, 53, 31, 42])
In [5]: jobs
Out[5]:
array([[0, 1, 1, 1, 1, 0],
[1, 0, 0, 1, 0, 1],
[1, 1, 0, 1, 0, 0],
[1, 0, 1, 1, 1, 1],
[1, 1, 0, 0, 1, 1],
[0, 1, 0, 0, 1, 0],
[1, 0, 0, 1, 1, 0],
[1, 1, 1, 1, 0, 1],
[1, 0, 0, 1, 0, 1],
[0, 1, 0, 1, 0, 0],
[0, 0, 1, 0, 1, 1],
[1, 0, 1, 1, 1, 1],
[0, 1, 1, 1, 1, 1],
[1, 0, 1, 1, 1, 1],
[0, 1, 1, 0, 1, 0],
[1, 0, 1, 0, 1, 0],
[1, 1, 1, 1, 1, 1],
[1, 0, 1, 0, 0, 1],
[0, 1, 0, 1, 1, 0],
[1, 1, 1, 0, 1, 0],
[1, 1, 1, 1, 1, 0],
[1, 0, 1, 0, 0, 1],
[0, 0, 0, 1, 1, 1],
[1, 1, 0, 1, 1, 1],
[1, 0, 1, 1, 0, 1],
[1, 1, 1, 1, 1, 1],
[1, 0, 1, 1, 1, 1],
[0, 0, 1, 1, 0, 0],
[1, 1, 0, 0, 1, 1],
[1, 1, 1, 1, 0, 0]])
In [6]: tot_job_costs = jobs # true_costs
In [7]: reg = linear_model.LinearRegression()
In [8]: reg.fit(jobs, tot_job_costs)
Out[8]: LinearRegression()
In [9]: reg.coef_
Out[9]: array([10., 20., 5., 53., 31., 42.])
In [10]: np.random.normal?
In [11]: noise = np.random.normal(0, scale=5, size=30)
In [12]: noisy_costs = tot_job_costs + noise
In [13]: noisy_costs
Out[13]:
array([113.94632664, 103.82109478, 78.73776288, 145.12778089,
104.92931235, 48.14676751, 94.1052639 , 134.64827785,
109.58893129, 67.48897806, 75.70934522, 143.46588308,
143.12160502, 147.71249157, 53.93020167, 44.22848841,
159.64772255, 52.49447057, 102.70555991, 69.08774251,
125.10685342, 45.79436364, 129.81354375, 160.92510393,
108.59837665, 149.1673096 , 135.12600871, 60.55375843,
107.7925208 , 88.16833899])
In [14]: reg.fit(jobs, noisy_costs)
Out[14]: LinearRegression()
In [15]: reg.coef_
Out[15]:
array([12.09045186, 19.0013987 , 3.44981506, 55.21114084, 33.82282467,
40.48642199])
In [16]:

How would I find the mode (stats) of pixel values of an image?

I'm using opencv and I'm able to get a pixel of an image-- a 3-dimensional tuple, via the code below. However, I'm not quite sure how to calculate the mode of the pixels values in the image.
import cv2
import numpy as np
import matplotlib.pyplot as plt
import numpy as np
import cv2
img =cv2.imread('C:\\Users\Moondra\ABEO.png')
#px = img[100,100] #gets pixel value
#print (px)
I tried,
from scipy import stats
stats.mode(img)[0]
But this returns an array shape of
stats.mode(img)[0].shape
(1, 800, 3)
Not sure how exactly stats is calculating the dimensions from which to choose the mode, but I'm looking for each pixel value (3 dimensional tuple) to be one element.
EDIT:
For clarity, I'm going to lay out exactly what I'm looking for.
Let's say we have an array that is of shape (3,5,3) and looks like this
array([[[1, 1, 2], #[1,1,2] = represents the RGB values
[2, 2, 2],
[1, 2, 2],
[2, 1, 1],
[1, 2, 2]],
[[1, 2, 2],
[2, 2, 2],
[2, 2, 2],
[1, 2, 2],
[1, 2, 1]],
[[2, 2, 1],
[2, 2, 1],
[1, 1, 2],
[2, 1, 2],
[1, 1, 2]]])
I would then convert it to an array that looks like this for easier calculation
Turn this into
array([[1, 1, 2],
[2, 2, 2],
[1, 2, 2],
[2, 1, 1],
[1, 2, 2],
[1, 2, 2],
[2, 2, 2],
[2, 2, 2],
[1, 2, 2],
[1, 2, 1],
[2, 2, 1],
[2, 2, 1],
[1, 1, 2],
[2, 1, 2],
[1, 1, 2]])
which is of shape(15,3)
I would like to calculate the mode by counting each set of RGB as follows:
[1,1,2] = 3
[2,2,2] = 4
[1,2,2] = 4
[2,1,1] = 2
[1,1,2] =1
Thank you.
From the description, it seems you are after the pixel that's occurring the most in the input image. To solve for the same, here's one efficient approach using the concept of views -
def get_row_view(a):
void_dt = np.dtype((np.void, a.dtype.itemsize * np.prod(a.shape[-1])))
a = np.ascontiguousarray(a)
return a.reshape(-1, a.shape[-1]).view(void_dt).ravel()
def get_mode(img):
unq, idx, count = np.unique(get_row_view(img), return_index=1, return_counts=1)
return img.reshape(-1,img.shape[-1])[idx[count.argmax()]]
We can also make use of np.unique with its axis argument, like so -
def get_mode(img):
unq,count = np.unique(img.reshape(-1,img.shape[-1]), axis=0, return_counts=True)
return unq[count.argmax()]
Sample run -
In [69]: img = np.random.randint(0,255,(4,5,3))
In [70]: img.reshape(-1,3)[np.random.choice(20,10,replace=0)] = 120
In [71]: img
Out[71]:
array([[[120, 120, 120],
[ 79, 105, 218],
[ 16, 55, 239],
[120, 120, 120],
[239, 95, 209]],
[[241, 18, 221],
[202, 185, 142],
[ 7, 47, 161],
[120, 120, 120],
[120, 120, 120]],
[[120, 120, 120],
[ 62, 41, 157],
[120, 120, 120],
[120, 120, 120],
[120, 120, 120]],
[[120, 120, 120],
[ 0, 107, 34],
[ 9, 83, 183],
[120, 120, 120],
[ 43, 121, 154]]])
In [74]: get_mode(img)
Out[74]: array([120, 120, 120])

Sum of arrays of different size [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
I have an array, whose elements are arrays of different sizes, say:
[[45, 96, 0.0, 96, 96, 96, 0.0], [04, 55, 06, 55, 04, 04, 02, 55]]
I want to find the sum of the two arrays, i.e.,
[49, 151, ...]
You can use something like this:
a.flat_map{|x| x.in_groups_of(a.max_by(&:size).size, 0)}.transpose.map(&:sum)
Or this:
a.max_by(&:size).map.with_index{|_, i| a.sum{|x| x[i]||0}}
Not very pretty, but works:
>> a = [[45, 96, 0.0, 96, 96, 96, 0.0], [04, 55, 06, 55, 04, 04, 02, 55]]
=> [[45, 96, 0.0, 96, 96, 96, 0.0], [4, 55, 6, 55, 4, 4, 2, 55]]
>> sorted_a = a.sort_by(&:size).reverse
=> [[4, 55, 6, 55, 4, 4, 2, 55], [45, 96, 0.0, 96, 96, 96, 0.0]]
>> zipped_a = sorted_a.first.zip(sorted_a.last)
=> [[4, 45], [55, 96], [6, 0.0], [55, 96], [4, 96], [4, 96], [2, 0.0], [55, nil]]
>> zipped_a.map{ |arr| arr.map{ |v| v || 0 } }.map(&:sum)
=> [49, 151, 6.0, 151, 100, 100, 2.0, 55]
First you have to sort the array starting the longest for zip to work properly. Zipping will then create nil values in the redundant values of the shorter arrays. So the next step is to replace these nils to zeroes (using the nested map) and finally you can sum the values.
You can try this way also
k =[]
for i in 0..ar.max_by(&:size).length-1 do
k << ar.map { |x| [x[i]] }
end
k.map(&:flatten).map{|a| a.compact.sum}
=> [49, 151, 6.0, 151, 100, 100, 2.0, 55]
a = [[45, 96, 0, 96, 96, 96, 0],
[ 4, 55, 6, 55, 4, 4, 2, 55]]
Array.new(a.max_by(&:size).size) { |i| a.reduce(0) { |t,e| t+e[i].to_i } }
#=>[49, 151, 6, 151, 100, 100, 2, 55]
Note that nil.to_i #=> 0 (ref).
Another example:
a = [[1], [2,3,4], [5,6]]
Array.new(a.max_by(&:size).size) { |i| a.reduce(0) { |t,e| t+e[i].to_i } }
#=> [8,9,4]

Sort by doesn't sort when includes is used in rails

I've got a distance attribute in my User model :
attr_accessor :distance
So when I calculate the distance for each user, and store it in the distance then I can sort them like :
users.sort_by!(&:distance)
And the users get sorted according to the distance appropriately. But when I include other associated methods i.e :
users.includes(:photo).sort_by!(&:distance)
This doesn't sort the users at all, why is this? How can I sort it with distance but include association as well?
the ! in the sort_by! method indicates that the object itself is changed rather than returns a different object.
When you call users.includes(:photo) this method returns a different object. So, what you are actually doing is like:
users2 = users.includes(:photo)
users2.sort_by!(&:distance)
This is why the users object is not sorted after you call sort_by!. A better way to do it might be
users = users.includes(:photo).sort_by(&:distance)
Well it does for me. I do "User", not "users"
User.includes(:photo).sort_by!(&:distance)
What does "users" variable hold, anyway?. Try User.
Edited with my example, here I user Enquiry for User and Score for Distance.
1.9.3p385 :059 > Enquiry.all.sort_by!(&:score).map &:score
Enquiry Load (0.7ms) SELECT `enquiries`.* FROM `enquiries`
=> [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 7, 8, 8, 10, 10]
1.9.3p385 :060 > Enquiry.includes(:follow_ups).sort_by!(&:score).map &:score
Enquiry Load (0.1ms) SELECT `enquiries`.* FROM `enquiries`
FollowUp Load (0.1ms) SELECT `follow_ups`.* FROM `follow_ups` WHERE `follow_ups`.`enquiry_id` IN (55, 64, 65, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 85, 86, 89, 91, 92, 93, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127)
=> [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 7, 8, 8, 10, 10]
1.9.3p385 :057 > enquiries = Enquiry.where(status_id: [1,2,3])
1.9.3p385 :061 > enquiries.includes(:follow_ups).sort_by!(&:score).map &:score
Enquiry Load (0.5ms) SELECT `enquiries`.* FROM `enquiries` WHERE `enquiries`.`status_id` IN (1, 2, 3)
FollowUp Load (0.2ms) SELECT `follow_ups`.* FROM `follow_ups` WHERE `follow_ups`.`enquiry_id` IN (68, 75, 78, 91, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 113, 114, 115, 116, 117, 120, 122, 123, 124, 125, 126, 127)
=> [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 5, 5, 5, 5, 5, 5, 5, 5, 7, 8, 8, 10]
Note: your question is wrong and you downvote me.
I believe you should do
users.sort_by!(&:distance).includes(:photo)
Use this:
User.includes(:photo).sort_by!(&:distance)
includes is used for Model, not for array.
so User is model name and users is array.
array have 'includes?' method and
Model have 'include' method
So use this
User.includes(:photo).sort_by!(&:distance)
instead of
users.includes(:photo).sort_by!(&:distance)

Undefined method for matrix, string to matrix

I am trying to work with matrixes; I have a model that has an attribute called "board", and its just a 4x4 matrix. I display this board in my view. So far so good. When I click a button, I send the param "board" with, for example, this structure:
{"utf8"=>"✓", "game_master"=>{"board"=>"Matrix[[0, 0, 0, 0], [0, 0, 1, 1], [0, 0, 1, 0], [1, 1, 0, 0]]"}, "commit"=>"Yolo"}
On the other side, in the controller, I try to recreate this board by creating a new gamemaster with board = Matrix[[0, 0, 0, 0], [0, 0, 1, 1], [0, 0, 1, 0], [1, 1, 0, 0]]. So far so good (NOT, I know that the param[:board] is just a string, that's my problem). Then, later on, when trying to iterate the matrix, I get this error:
undefined method `each_with_index' for "Matrix[[0, 0, 0, 0], [0, 0, 1, 1], [0, 0, 1, 0], [1, 1, 0, 0]]":String
Clearly, I bound :board to a string NOT a matrix. How would I go around converting that string into the corresponding matrix?
Thanks
UPDATE:
game_masters_controller.rb
def step
#game_master = GameMaster.new(game_master_params)
#game_master.step
respond_to do |format|
format.js
end
end
And:
private
def game_master_params
params.require(:game_master).permit(:board)
end
game_master.rb
def initialize(attributes = {})
attributes.each do |name, value|
send("#{name}=", value)
end
if(self.board == nil)
self.board = get_new_board
end
end
Simply do:
arr = params[:game_master][:board].split(',').map(&:to_i).each_slice(4).to_a
# => [[0, 0, 0, 0], [0, 0, 1, 1], [0, 0, 1, 0], [0, 1, 0, 0]]
require 'matrix'
matrix = Matrix[*arr]
# => Matrix[[0, 0, 0, 0], [0, 0, 1, 1], [0, 0, 1, 0], [0, 1, 0, 0]]
Quick and dirty and not very secure:
class GameMaster
...
def board=(attr)
#board = eval attr
end
end
I would not run eval on something that gets submitted via a form. If the matrix is always 4x4, I would probably just submit the values in one long comma separated string like 0,0,0,1,1,1,0 .... Then I would use String#split to turn the large string into an array. Once you have one big array you could loop through it to generate an array of arrays that you can send to Matrix.new
string_params = 0,1,1,0,0,1
array_of_string = string_params.split(',')
array_of_arrays = array_of_string.each_slice(4).to_a
matrix = Matrix.new(array_of_arrays)
That should point you in the right direction.
Good luck!
Try this code:
(as the other answers mentioned, it's not secure to eval code coming from an input)
require 'matrix'
m = eval "Matrix[[0, 0, 0, 0], [0, 0, 1, 1], [0, 0, 1, 0], [1, 1, 0, 0]]"
=> Matrix[[0, 0, 0, 0], [0, 0, 1, 1], [0, 0, 1, 0], [1, 1, 0, 0]]
m.transpose
=> Matrix[[0, 0, 0, 1], [0, 0, 0, 1], [0, 1, 1, 0], [0, 1, 0, 0]]
Requiring the matrix.rb file will give you access to a lot of useful methods, check the documentation for further information.
http://ruby-doc.org/stdlib-2.1.0/libdoc/matrix/rdoc/Matrix.html

Resources