Help to set a penalty

Hello,

I’m stuck with my code.

I want to assign a student i to a course j. Each student has chosen their 4 favorite choices.
I have 158 i and 34 j.

Based on the students’ preferences, I would like to impose a penalty p[i,j].
I would like to set the following values for p[i,j]:
p[i,j]=0 for his first choice
p[i,j]=5 for his second choice
p[i,j]=20 for his third choice
p[i,j]=100 for his fourth choice
p[i,j]=1000 if the course is not in the student’s choice

and then I would like, using println(), to have julia display me:
penalty 1 = 0
penalty 2 = 5
penalty 3 = 20

Could someone help me?

Welcome! I honestly do not understand your question. It would be much easier to help you if you post (a minimal working example of) your code and point us to the part where you are stuck.

Where do you have this data about student preferences stored?

Do you mean that you want just these penalty values printed as above?

julia> penalties = [0, 5, 20, 100, 1000];

julia> for i in 1:5
         println("penalty $i = ", penalties[i])
       end
penalty 1 = 0
penalty 2 = 5
penalty 3 = 20
penalty 4 = 100
penalty 5 = 1000

If not, please explain what kind of output you have in mind, with examples.

1 Like

Thank you very much for your answer!

I will explain you more precisely my problem:

I need to assign students to courses based on their preferences. These preferences are collected in an excel file. In this file, there are five columns “student name” “choice 1” “choice 2” “choice 3” “choice 4”.

The final objective will be to maximize student satisfaction by minimizing penalties.

First, I need to set the value of the penalties, and this is where I get stuck.
How to fix that p[i,j]=0 if the student has his first choice, 5 if he has his second choice,… ?

I hope to have been clearer…

I would like for example that p[3,2] = 0, p[3,4]=5, p[3,13]=20, p[3,1]=100 and p[3, (all other j)]= 1000

Maybe this? (Slightly simplified with 10 courses and 5 students picking 3 of these to keep the output a bit more manageable):

julia> using StatsBase

julia> courses = 1:10
1:10

julia> student_choices = [sample(1:10, 3, replace = false) for _ ∈ 1:5]
5-element Vector{Vector{Int64}}:
 [1, 4, 9]
 [7, 1, 5]
 [8, 7, 10]
 [6, 10, 7]
 [10, 7, 6]

julia> p = zeros(length(courses), length(student_choices))
10×5 Matrix{Float64}:
 0.0  0.0  0.0  0.0  0.0
 0.0  0.0  0.0  0.0  0.0
 0.0  0.0  0.0  0.0  0.0
 0.0  0.0  0.0  0.0  0.0
 0.0  0.0  0.0  0.0  0.0
 0.0  0.0  0.0  0.0  0.0
 0.0  0.0  0.0  0.0  0.0
 0.0  0.0  0.0  0.0  0.0
 0.0  0.0  0.0  0.0  0.0
 0.0  0.0  0.0  0.0  0.0

julia> for i ∈ axes(p, 1), j ∈ axes(p, 2)
           if i ∉ student_choices[j]
               p[i, j] = 1000
           else
               p[i, j] = getindex([0, 5, 20], findfirst(==(i), student_choices[j]))
           end
       end

julia> p
10×5 Matrix{Float64}:
    0.0     5.0  1000.0  1000.0  1000.0
 1000.0  1000.0  1000.0  1000.0  1000.0
 1000.0  1000.0  1000.0  1000.0  1000.0
    5.0  1000.0  1000.0  1000.0  1000.0
 1000.0    20.0  1000.0  1000.0  1000.0
 1000.0  1000.0  1000.0     0.0    20.0
 1000.0     0.0     5.0    20.0     5.0
 1000.0  1000.0     0.0  1000.0  1000.0
   20.0  1000.0  1000.0  1000.0  1000.0
 1000.0  1000.0    20.0     5.0     0.0

Here in p every column is a student and row is a course - so e.g. the first student (first column) has a penalty of 0 in the first row (as that’s their first choice), then 5 in row 4 as course 4 is their second choice, and 20 in row 9. All other rows are 1000 as the courses haven’t been chosen.

I’ll suggest a more verbose option using DataFrames. My result is basically the same as nilshg.

using DataFrames#, XLSX
I = 158
J = 34
# Use the XLSX package (https://felipenoris.github.io/XLSX.jl/stable/tutorial/)
# to read df from your Excel file instead of the line below which has random data.
df = DataFrame(student = 1:I,
               choice1 = rand(1:J, I),
               choice2 = rand(1:J, I),
               choice3 = rand(1:J, I),
               choice4 = rand(1:J, I))
p = fill(1000, I, J)
for j in 1:J
    for i in 1:I
        if j == df[i, :choice1]
            p[i, j] = 0
        elseif j == df[i, :choice2]
            p[i, j] = 5
        elseif j == df[i, :choice3]
            p[i, j] = 20
        elseif j == df[i, :choice4]
            p[i, j] = 100
        end
    end
end
display(p)
2 Likes

Thank you very much for your answer.

I wrote the following code inspired by yours but it does not work. Do you see where the error comes from?

n=1 
while !ismissing(ws[n+1,1]) 
for i in 1:n-1, j in 1:34
        if j==ws[1+n,4]
            p[i,j] == 0
        elseif j==ws[1+n,6]
            p[i,j] == 5
        elseif j==ws[1+n,8]
            p[i,j] == 20
        elseif j==ws[1+n,10]
            p[i,j] == 100
        else
            p[i,j] == 1000
        end
    end
    global n=n+1
end

I tried to use your code and implement it to my data but I don’t understand what I have to change to be able to do it…

Thank you so much for your help!

It looks like there may be several problems. For one, there are no statements inside your while loop which change the values in ws, so you are either never entering the while loop or stuck inside it forever. I also think you may misunderstand what the ismissing function does. I will need more information from you to be able to help.

Please try to break your problem down into small minimum working examples (MWEs), so that we can copy and paste your code and see exactly what you are seeing. For example, this code is missing lines which define ws and p. Also please be more specific about what “does not work”. Include the error you are seeing or the result which is different from what you expect. Error messages will tell you what line of your code failed and give you a hint about what was wrong. Often the exercise of creating a MWE will help you fix problems yourself. Please read: make it easier to help you - Meta Discussion - JuliaLang