Turn list clockwise for one time - python

How I can rotate list clockwise one time? I have some temporary solution, but I'm sure there is a better way to do it.
I want to get from this
Index: 0 1 2 3 4 5 6 7 8 9
Count: 0 2 4 4 5 6 6 7 7 7
to this:
Index: 0 1 2 3 4 5 6 7 8 9
Count: 0 0 2 4 4 5 6 6 7 7
And my temporary "solution" is just:
temporary = [0, 2, 4, 4, 5, 6, 6, 7, 7, 7]
test = [None] * len(temporary)
test[0] = temporary[0]
for index in range(1, len(temporary)):
test[index] = temporary[index - 1]

You might use temporary.pop() to discard the last item and temporary.insert(0, 0) to add 0 to the front.

Alternatively in one line:
temporary = [0] + temporary[:-1]

Related

How to remove consecutive pairs of opposite numbers from Pandas Dataframe?

How can i remove consecutive pairs of equal numbers with opposite signs from a Pandas dataframe?
Assuming i have this input dataframe
incremental_changes = [2, -2, 2, 1, 4, 5, -5, 7, -6, 6]
df = pd.DataFrame({
'idx': range(len(incremental_changes)),
'incremental_changes': incremental_changes
})
idx incremental_changes
0 0 2
1 1 -2
2 2 2
3 3 1
4 4 4
5 5 5
6 6 -5
7 7 7
8 8 -6
9 9 6
I would like to get the following
idx incremental_changes
0 0 2
3 3 1
4 4 4
7 7 7
Note that the first 2 could either be idx 0 or 2, it doesn't really matter.
Thanks
Can groupby consecutive equal numbers and transform
import itertools
def remove_duplicates(s):
''' Generates booleans that indicate when a pair of ints with
opposite signs are found.
'''
iter_ = iter(s)
for (a,b) in itertools.zip_longest(iter_, iter_):
if b is None:
yield False
else:
yield a+b == 0
yield a+b == 0
>>> mask = df.groupby(df['incremental_changes'].abs().diff().ne(0).cumsum()) \
['incremental_changes'] \
.transform(remove_duplicates)
Then
>>> df[~mask]
idx incremental_changes
2 2 2
3 3 1
4 4 4
7 7 7
Just do rolling, then we filter the multiple combine
s = df.incremental_changes.rolling(2).sum()
s = s.mask(s[s==0].groupby(s.ne(0).cumsum()).cumcount()==1)==0
df[~(s | s.shift(-1))]
Out[640]:
idx incremental_changes
2 2 2
3 3 1
4 4 4
7 7 7

Function for scaling numbers in a pd.DF with a list of numbers

Pretty new to Python. I'm trying to create a function which should look at a csv file, with an ID number, Name, and then N columns of numbers from different tests and then scale/round the numbers so they can be compared to the Danish grading system from [-3, 00, 02, 4, 7, 10, 12].
My script below does exactly that, but my function only returns the last result of the DF.
Here's the CSV, I use for testing:
StudentID,Name,Assignment1,Assignment2,Assignment3
s123456,Michael Andersen,7,5,4
s123789,Bettina Petersen,12,3,10
s123468,Thomas Nielsen,-3,7,2
s123579,Marie Hansen,10,12,12
s123579,Marie Hansen,10,12,12
s127848, Andreas Nielsen,2,2,2
s120799, Mads Westergaard,12,12,10
Its worth to mention that i need these functions separate, for my main script.
I've made a simple function which loads the file using pandas:
import pandas as pd
def dataLoad(filename):
grades = pd.read_csv(filename)
return grades
then I've written this script for the rounding of the numbers:
# Importing modules
import pandas as pd
import numpy as np
#Loading in the function dataLoad
from dataLoad import dataLoad
#Defining my data witht the function
grades=dataLoad('Karakterer.csv')
def roundGrade(grades):
#Dropping the two first columns of the pd.DF
grades=grades.drop(['StudentID','Name'],axis=1)
#Making the pd.DF into a numpy array
sample_grades=np.array(grades)
#Setting the parameters of the scale to round up to
grade_Scale = np.array([-3,0,2,4,7,10,12])
#Defining i, so i get gradually bigger with each cycle
i=0
#Making a for loop, which rounds every number in every row of the given array
for i in range(0,len(grades)):
grouped = [min(grade_Scale,key=lambda x:abs(grade-x)) for grade in sample_grades[i,:]]
#Making i 1 time bigger for each cycle
i=i+1
return grouped
Tell if you need some more information about the script, cheers guys!
For improve performance use numpy:
#assign output to df instead grades for possible assign values back in last step
df = dataLoad('Karakterer.csv')
grades = df.drop(['StudentID','Name'],axis=1)
grade_Scale = np.array([-3,0,2,4,7,10,12])
grades=df.drop(['StudentID','Name'],axis=1)
print (grades)
Assignment1 Assignment2 Assignment3
0 7 5 4
1 12 3 10
2 -3 7 2
3 10 12 12
4 10 12 12
5 2 2 2
6 12 12 10
arr = grades.values
a = grade_Scale[np.argmin(np.abs(arr[:,:, None] - grade_Scale[None,:]), axis=2)]
print (a)
[[ 7 4 4]
[12 2 10]
[-3 7 2]
[10 12 12]
[10 12 12]
[ 2 2 2]
[12 12 10]]
Last if need assign back output to columns:
df[grades.columns] = a
print (df)
StudentID Name Assignment1 Assignment2 Assignment3
0 s123456 Michael Andersen 7 4 4
1 s123789 Bettina Petersen 12 2 10
2 s123468 Thomas Nielsen -3 7 2
3 s123579 Marie Hansen 10 12 12
4 s123579 Marie Hansen 10 12 12
5 s127848 Andreas Nielsen 2 2 2
6 s120799 Mads Westergaard 12 12 10
Explanation:
It is used this solution but for multiple columns:
Idea is compare 2d array created from all columns from DataFrame to arr by array grade_Scale. So you can use broadcasting for possible create 3d array of differences between them with absolute values:
print (np.abs(arr[:,:, None] - grade_Scale[None,:]))
[[[10 7 5 3 0 3 5]
[ 8 5 3 1 2 5 7]
[ 7 4 2 0 3 6 8]]
[[15 12 10 8 5 2 0]
[ 6 3 1 1 4 7 9]
[13 10 8 6 3 0 2]]
[[ 0 3 5 7 10 13 15]
[10 7 5 3 0 3 5]
[ 5 2 0 2 5 8 10]]
[[13 10 8 6 3 0 2]
[15 12 10 8 5 2 0]
[15 12 10 8 5 2 0]]
[[13 10 8 6 3 0 2]
[15 12 10 8 5 2 0]
[15 12 10 8 5 2 0]]
[[ 5 2 0 2 5 8 10]
[ 5 2 0 2 5 8 10]
[ 5 2 0 2 5 8 10]]
[[15 12 10 8 5 2 0]
[15 12 10 8 5 2 0]
[13 10 8 6 3 0 2]]]
Then use position by minimal values by numpy.argmin per axis=2 (working with 3rd axis in 3d array):
print (np.argmin(np.abs(arr[:,:, None] - grade_Scale[None,:]), axis=2))
[[4 3 3]
[6 2 5]
[0 4 2]
[5 6 6]
[5 6 6]
[2 2 2]
[6 6 5]]
And last use indexing by grade_Scale values:
print (grade_Scale[np.argmin(np.abs(arr[:,:, None] - grade_Scale[None,:]), axis=2)])
[[ 7 4 4]
[12 2 10]
[-3 7 2]
[10 12 12]
[10 12 12]
[ 2 2 2]
[12 12 10]]
You are re-assigning the new calculated value to grouped in every iteration. One way to handle that is to declare a variable and append,
def roundGrade(grades):
i = 0
grouped = []
for i in range(0,len(grades)):
grouped.append([min(grade_Scale,key=lambda x:abs(grade-x)) for grade in sample_grades[i,:]])
i=i+1
return grouped
Now call the function,
roundGrade(np.array([[ 7, 5, 4],
[12, 3, 10]]))
[[7, 4, 4], [12, 2, 10]]

Shuffle "coupled" elements in python array

Let's say I have this array:
np.arange(9)
[0 1 2 3 4 5 6 7 8]
I would like to shuffle the elements with np.random.shuffle but certain numbers have to be in the original order.
I want that 0, 1, 2 have the original order.
I want that 3, 4, 5 have the original order.
And I want that 6, 7, 8 have the original order.
The number of elements in the array would be multiple of 3.
For example, some possible outputs would be:
[ 3 4 5 0 1 2 6 7 8]
[ 0 1 2 6 7 8 3 4 5]
But this one:
[2 1 0 3 4 5 6 7 8]
Would not be valid because 0, 1, 2 are not in the original order
I think that maybe zip() could be useful here, but I'm not sure.
Short solution using numpy.random.shuffle and numpy.ndarray.flatten functions:
arr = np.arange(9)
arr_reshaped = arr.reshape((3,3)) # reshaping the input array to size 3x3
np.random.shuffle(arr_reshaped)
result = arr_reshaped.flatten()
print(result)
One of possible random results:
[3 4 5 0 1 2 6 7 8]
Naive approach:
num_indices = len(array_to_shuffle) // 3 # use normal / in python 2
indices = np.arange(num_indices)
np.random.shuffle(indices)
shuffled_array = np.empty_like(array_to_shuffle)
cur_idx = 0
for idx in indices:
shuffled_array[cur_idx:cur_idx+3] = array_to_shuffle[idx*3:(idx+1)*3]
cur_idx += 3
Faster (and cleaner) option:
num_indices = len(array_to_shuffle) // 3 # use normal / in python 2
indices = np.arange(num_indices)
np.random.shuffle(indices)
tmp = array_to_shuffle.reshape([-1,3])
tmp = tmp[indices,:]
tmp.reshape([-1])

numpy.random.randint does not return a list separte by comma

I am running this code:
import numpy as np
Z=np.ones(10)
I = np.random.randint(0,len(Z),20).
print I
#[9 0 0 1 0 2 3 4 3 3 2 2 7 8 1 9 9 2 1 7]
#so this instruction does not work
print Z[I]
return a list without where the elelements does not separates by comma as mentioned here randint
The output on that page shows the interpreter (or repr) output. Also, I changed it to randint and removed the period that would have thrown a syntax error.
import numpy as np
I = np.random.randint(0, 10, 10)
print(I) # => [9 4 2 7 6 3 4 5 6 2]
print(repr(I)) # => array([9, 4, 2, 7, 6, 3, 4, 5, 6, 2])
print(type(I)) # => <type 'numpy.ndarray'>
L = list(I)
print(L) # => [9, 4, 2, 7, 6, 3, 4, 5, 6, 2]
Changing the randomint to randint works for me:
Z=np.arange(10)
I = np.random.randint(0,len(Z),20)
print I
#[9 0 0 1 0 2 3 4 3 3 2 2 7 8 1 9 9 2 1 7]
#so this instruction works for me
print Z[I]
# [3 9 6 6 7 7 7 3 7 5 5 2 1 1 5 7 1 0 7 4]

Unknown number of iterations to complete the sort

I am heading towards sorting algorithms. I have just started to learn the Insertion Sort. I needed to make a solution for a already sorted list with an unsorted number at the end. So the problem now is that the loop skips one iteration or adds another duplicate one. Here is what I mean:
When I try to sort this list: {2, 4, 6, 8 ,3} I get this:
2 4 6 8 3
2 4 6 8 8
2 4 6 6 8
2 4 4 6 8
2 3 4 6 8
2 3 4 6 8 #duplicated! ^
And when I try to sort this list: {2, 4, 6, 8, 1} I get this:
2 4 6 8 8
2 4 6 6 8
2 4 4 6 8
2 2 4 6 8
1 2 4 6 8 #no duplicates
How can I know how many iteration do I need to complete the sort? Here's how I sort:
ar = list(map(int, input().split()))
mins = ar[-1]
for i in range(len(ar)-1, 0, -1):
if ar[i-1] > mins: ar[i] = ar[i-1]
else: ar[i] = mins
print(*ar)
if mins < ar[0]: ar[0] = mins
print(*ar)
Simply break the loop when you find a[i-1] <= mins.
ar = [2, 4, 6, 8 ,1]
mins = ar[-1]
for i in range(len(ar)-1, 0, -1):
if ar[i-1] > mins:
ar[i] = ar[i-1]
else:
ar[i] = mins
break
print(ar)
if mins < ar[0]: ar[0] = mins
print(ar)

Categories

Resources