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.
    – furas
    Commented Jul 31, 2020 at 11:45
  • why do you create DataFrame inside for-loop if you don't use it ?
    – furas
    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.
    – furas
    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
4
  • 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.
    – Cmagelssen
    Commented Jul 31, 2020 at 12:28
  • 1
    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()
    – furas
    Commented Jul 31, 2020 at 13:14
  • 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
    – Cmagelssen
    Commented Jul 31, 2020 at 13:22
  • 1
    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.
    – furas
    Commented Jul 31, 2020 at 13:26
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
  • Perfect. More readable. The only thing is that I can only have a maximum of 3 runs in each course.
    – Cmagelssen
    Commented Jul 31, 2020 at 12:06
  • @ChristianMagelssen What do you mean by 3 runs? max 3 of a kind?
    – alec_djinn
    Commented Jul 31, 2020 at 12:19
  • Yes. So a total of 12 runs (3 in each course). Straight-gliding counts as one course
    – Cmagelssen
    Commented Jul 31, 2020 at 12:28
  • @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.
    – alec_djinn
    Commented Jul 31, 2020 at 12:33
  • 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.
    – alec_djinn
    Commented Jul 31, 2020 at 12:40
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

Not the answer you're looking for? Browse other questions tagged or ask your own question.