0

I have created a static method that creates a random training protocol for the participants involved in an experiment. The method works but I want the training day to always start with 'STRAIGHT-GLIDING'. Is there a simple way I can do this in Pandas?

I have tried to use .loc but it turns out that this overwrites the existing values, and that's not what I want.

Thanks Christian

    @staticmethod
    def allokeringRandom(printToCSV=False):
        dn = []
        for i in range(1, 4):
            df = pd.DataFrame()
            loype = ['STRAIGHT-GLIDING','STRAIGHT-GLIDING','LØYPE 1', 'LØYPE 1', 'LØYPE 1', 'LØYPE 2', 'LØYPE 2', 'LØYPE 2', 'LØYPE 3', 'LØYPE 3', 'LØYPE 3']
            dn.append(random.sample(loype, len(loype)))
        df = pd.DataFrame(dn).transpose()
        df = df.rename(columns={0: "Treningsdag 1", 1: "Treningsdag 2", 2: "Treningsdag 3"})
        if printToCSV == True:
            df.to_csv('test3.csv')
3
  • I don't understand what you try to do. Better show some example data and what result you expect. Commented Jul 31, 2020 at 11:45
  • why do you create DataFrame inside for-loop if you don't use it ? Commented Jul 31, 2020 at 11:45
  • Maybe you should add STRAIGHT-GLIDING before for-loop - dn = ['STRAIGHT-GLIDING'] - and then it will be first on list. Commented Jul 31, 2020 at 11:46

3 Answers 3

1

if you want it at start then you should add it manually as first

loype = ['LØYPE 1', 'LØYPE 1', 'LØYPE 1', 'LØYPE 2', 'LØYPE 2', 'LØYPE 2', 'LØYPE 3', 'LØYPE 3', 'LØYPE 3']
dn.append(['STRAIGHT-GLIDING','STRAIGHT-GLIDING'] + random.sample(loype, len(loype)))

BTW: if you want all elements but in random order then you can use shuffle

loype = ['LØYPE 1', 'LØYPE 1', 'LØYPE 1', 'LØYPE 2', 'LØYPE 2', 'LØYPE 2', 'LØYPE 3', 'LØYPE 3', 'LØYPE 3']
random.shuffle(loype)
dn.append(['STRAIGHT-GLIDING','STRAIGHT-GLIDING'] + loype)

Minimal working code

import pandas as pd
import random

dn = []
loype = ['LØYPE 1', 'LØYPE 1', 'LØYPE 1', 'LØYPE 2', 'LØYPE 2', 'LØYPE 2', 'LØYPE 3', 'LØYPE 3', 'LØYPE 3']

for _ in range(3):
    random.shuffle(loype)
    dn.append(['STRAIGHT-GLIDING','STRAIGHT-GLIDING'] + loype)

df = pd.DataFrame(dn).transpose()
df = df.rename(columns={0: "Treningsdag 1", 1: "Treningsdag 2", 2: "Treningsdag 3"})

print(df)

Result

       Treningsdag 1     Treningsdag 2     Treningsdag 3
0   STRAIGHT-GLIDING  STRAIGHT-GLIDING  STRAIGHT-GLIDING
1   STRAIGHT-GLIDING  STRAIGHT-GLIDING  STRAIGHT-GLIDING
2            LØYPE 1           LØYPE 3           LØYPE 2
3            LØYPE 2           LØYPE 1           LØYPE 1
4            LØYPE 2           LØYPE 3           LØYPE 2
5            LØYPE 1           LØYPE 2           LØYPE 3
6            LØYPE 1           LØYPE 3           LØYPE 3
7            LØYPE 3           LØYPE 1           LØYPE 1
8            LØYPE 3           LØYPE 1           LØYPE 3
9            LØYPE 3           LØYPE 2           LØYPE 2
10           LØYPE 2           LØYPE 2           LØYPE 1
Sign up to request clarification or add additional context in comments.

4 Comments

Thanks. This was really useful. The only problem I found with the shuffle method is that is that it does not return anything; it just changes the list, which means that if I assign it to a variable, it returns null. But you solution worked perfectly with the sample method.
shuffle chages original list (it works in-place) - but in most situations it doesn't makes problem. But if you want to keep original list then you can do new_list = loype.copy()
Thanks. Another thing I came to realise from your reading your code is that it is possible to give the .append() method multiple objects. I thought this was only possible with the .insert() method and that this was the major difference between the two methods. But here you passed two lists but it worked
first I use + to join two lists into one list and later I use append() to add this one list to dn - so append() adds only one object like insert(). The only difference between append() and insert() is that append() always insert at the end.
1

You can simply overwrite the first row of the DataFrame after the df.transpose() call.

df.iloc[0] = ['STRAIGHT-GLIDING','STRAIGHT-GLIDING','STRAIGHT-GLIDING']

However, I would suggest a completely different way of building your DataFrame. Starts with a dictionary and add the random values to it, then convert it to a DataFrame. I found this implementation way easier to read.

loype = ['STRAIGHT-GLIDING','LØYPE 1', 'LØYPE 2', 'LØYPE 3']
#start with 'STRAIGHT-GLIDING' for each training day
d = {
    "Treningsdag 1":['STRAIGHT-GLIDING'],
    "Treningsdag 2":['STRAIGHT-GLIDING'],
    "Treningsdag 3":['STRAIGHT-GLIDING'],
}
#add random exercises
for n in range(10):
    for k in d:
        d[k].append(*random.sample(loype, 1))
#make a DataFrame        
df = pd.DataFrame(d)

print(df)

       Treningsdag 1     Treningsdag 2     Treningsdag 3
0   STRAIGHT-GLIDING  STRAIGHT-GLIDING  STRAIGHT-GLIDING
1            LØYPE 3           LØYPE 2           LØYPE 2
2            LØYPE 3  STRAIGHT-GLIDING           LØYPE 3
3            LØYPE 2  STRAIGHT-GLIDING  STRAIGHT-GLIDING
4            LØYPE 2  STRAIGHT-GLIDING           LØYPE 3
5            LØYPE 3           LØYPE 3           LØYPE 3
6            LØYPE 2           LØYPE 3           LØYPE 2
7            LØYPE 3           LØYPE 3           LØYPE 3
8            LØYPE 2  STRAIGHT-GLIDING           LØYPE 2
9            LØYPE 3           LØYPE 1           LØYPE 2
10           LØYPE 2           LØYPE 1           LØYPE 1

Integrating the specs from the latest OP's comments:

exercises = ['STRAIGHT-GLIDING','LØYPE 1', 'LØYPE 2', 'LØYPE 3']
max_reps = 3

training_days = ["Treningsdag 1","Treningsdag 2","Treningsdag 3"]
exercises_per_day = 12

loype = exercises * max_reps #list with all exercises, starting with 'STRAIGHT-GLIDING'

d = {}
for day in training_days:
    start, end = loype[0], loype[1: exercises_per_day]
    random.shuffle(end) #starts with the same exercise, shuffle the others
    d[day] = [start, *end]
    
df = pd.DataFrame(d)

print(df)

       Treningsdag 1     Treningsdag 2     Treningsdag 3
0   STRAIGHT-GLIDING  STRAIGHT-GLIDING  STRAIGHT-GLIDING
1            LØYPE 1  STRAIGHT-GLIDING  STRAIGHT-GLIDING
2            LØYPE 3           LØYPE 3           LØYPE 1
3   STRAIGHT-GLIDING           LØYPE 3           LØYPE 3
4            LØYPE 3           LØYPE 2           LØYPE 2
5            LØYPE 2           LØYPE 2           LØYPE 1
6   STRAIGHT-GLIDING           LØYPE 2           LØYPE 2
7            LØYPE 2  STRAIGHT-GLIDING           LØYPE 2
8            LØYPE 1           LØYPE 1  STRAIGHT-GLIDING
9            LØYPE 1           LØYPE 3           LØYPE 1
10           LØYPE 2           LØYPE 1           LØYPE 3
11           LØYPE 3           LØYPE 1           LØYPE 3

5 Comments

Perfect. More readable. The only thing is that I can only have a maximum of 3 runs in each course.
@ChristianMagelssen What do you mean by 3 runs? max 3 of a kind?
Yes. So a total of 12 runs (3 in each course). Straight-gliding counts as one course
@ChristianMagelssen I have modified the answer accordingly. Let me know if you need additional comments in the code. It looks quite self-explanatory to me.
You can further generalize training_days, in case you want to have hundreds of them, simply by setting a range to it training_days = range(1, 100, 1) and using an f-string to generate the key of the dictionary d[f'Treningsdag {day}'] = [start, *end]. That is up to you.
0

Pass the series through apply() that uses sorted with a custom key

import random
dn = []
for i in range(1, 4):
    df = pd.DataFrame()
    loype = ['STRAIGHT-GLIDING','STRAIGHT-GLIDING','LØYPE 1', 'LØYPE 1', 'LØYPE 1', 'LØYPE 2', 'LØYPE 2', 'LØYPE 2', 'LØYPE 3', 'LØYPE 3', 'LØYPE 3']
    dn.append(random.sample(loype, len(loype)))
df = pd.DataFrame(dn).transpose()
df = df.rename(columns={0: "Treningsdag 1", 1: "Treningsdag 2", 2: "Treningsdag 3"})
df = df.apply(lambda s: sorted(s,key=lambda x: "A" if x=="STRAIGHT-GLIDING" else x))
print(df.to_string(index=False))

output

    Treningsdag 1     Treningsdag 2     Treningsdag 3
 STRAIGHT-GLIDING  STRAIGHT-GLIDING  STRAIGHT-GLIDING
 STRAIGHT-GLIDING  STRAIGHT-GLIDING  STRAIGHT-GLIDING
          LØYPE 1           LØYPE 1           LØYPE 1
          LØYPE 1           LØYPE 1           LØYPE 1
          LØYPE 1           LØYPE 1           LØYPE 1
          LØYPE 2           LØYPE 2           LØYPE 2
          LØYPE 2           LØYPE 2           LØYPE 2
          LØYPE 2           LØYPE 2           LØYPE 2
          LØYPE 3           LØYPE 3           LØYPE 3
          LØYPE 3           LØYPE 3           LØYPE 3
          LØYPE 3           LØYPE 3           LØYPE 3

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.