so I want to generate 𝑛 random, floating-point numbers between 0 and 1 and calculate the mean. Then repeat this 𝑚 times. I want to do a Histogram with this later.
This is what I came up with so far:
import numpy as np
import matplotlib.pyplot as plt
import random
#random float number between 0 and 1
x=np.random.random(n)
print(np.mean(x))
#building my function
def myFunction(n,m):
for n in x:
return(np.mean(x))
print(myFunction(5,10))
So of course this will only give me one mean value, and my question is how can I build my function to repeat itself 𝑚 times?
You don't need any loops.
Instead of generating a random array of n elements m, times, make an n x m array and use numpy's API to take your mean along the second axis:
import numpy
m = 10
n = 5
x = numpy.random.random(size=(n, m))
means = x.mean(axis=1)
Your attempt is a bit off. You pass n to the function, but you also then do for n in x. So n is overwritten, but x is also a single number, so it won't iterate how you are wanting it to. For loops can be nested, so you can initialise two lists, one which will be the means of each run in m, and one which will store all the values in each run inside m to return the mean.
def myFunction(n,m):
mean_list = []
for _ in range(m):
inner_list = []
for i in range(n):
inner_list.append(np.random.random())
mean_list.append(np.mean(inner_list))
return mean_list
This returns a list of means, m means to be exact. So
myFunction(5, 10)
returns (as an example)
[0.6635917645438433, 0.5569813806972684, 0.5869406453209447, 0.48729391271790945, 0.6276934115328581, 0.6109176360963581, 0.45357579860009095, 0.611056289890255, 0.15579494695767637, 0.5097066251736436]
Please see the comments in the code below for an explanation:
import numpy as np
import matplotlib.pyplot as plt
import random
#Your function should contain a loop:
def myFunction(n,m):
# This loop is the "repeat M times" part. The variable "i"
# will count 0 to M - 1, a total of "M" iterations
for i in range(m):
#Everything inside here will run "M" times
x = np.random.random(n) # Here we generate N random numbers
mean = np.mean(x) #Here is the mean
#Print the means
print("Iteration {} mean: {}".format(i, mean))
myFunction(5,10) #Call it with N = 5 and M = 10
Your code doesn't work because return ends the function, you would have to either return a list of some sort or data container (1). Another alternative would be to run an outside loop with the parameters that you want(2).
ex. 1
def mf(m, n):
return np.mean(n)
data = []
for x in range(m):
data.append([x, mf(m, n)])
2
def mf(m, n):
data = []
for x in range(m):
data.append([x, np.mean(n)])
return data
There are some issues with your code.
First, since you created x outside of the function, it creates n random values just once and reuses the same x value resulting in the same mean.
Second, when you use return inside a for loop, it will stop the for loop and exit the function in the first iteration resulting in only one output.
A better way
import numpy as np # numpy has random module
import matplotlib.pyplot as plt
def myFunction(n,m):
list = []
for i in range(m):
x = np.random.rand(n)
list.append(np.mean(x))
return np.array(list)
# Even better way is to use list comprehension
def myFunction(n,m):
list = np.array([np.mean(np.random.rand(n)) for i in range(m)])
return list
You need to create the random array in the loop, so you get different random numbers each time.
The loop should collect all the results into a list, and return the list. You can do this using a list comprehension.
def myFunction(n,m):
return [np.mean(np.random(n)) for _ in range(m)]
Related
I have an array of size nxm and want to take the first 10 rows and perform calculations, then take the next 10 rows perform calculations, etc. But this is hard coded, how can I make a loop?
Code Attempted:
import numpy as np
total = []
x= np.random.random((100,4))
a = np.average(x[:10])
total.append(a)
a = np.average(x[10:20])
total.append(a)
a = np.average(x[20:30])
....
Goal:
for *this array*:
# to something
# append value
# go back and get next 10 values
It looks like you want the following.
import numpy as np
x = np.random.random((100,4))
L = 10
k = 100//L
total = [np.average(x[L*i:L*(i+1)]) for i in range(k)]
If you'd rather implement this using a loop rather than list comprehension,
import numpy as np
x = np.random.random((100,4))
L = 10
k = 100//L
total = []
for i in range(k):
total.append(np.average(x[L*i:L*(i+1)]))
As an alternative, here's an approach using a 3-dimensional reshape.
x= np.random.random((100,4))
L = 10 #window length
n = x.shape[1] #number of columns
total = a.reshape(-1,10,n).mean(axis = (1,2))
import numpy as np
x = np.random.random((100,4))
a = 10
b = 100//a
c = 4
You want the array of average numbers of the first 10 * 4 part, the second 10 * 4 part,..., right?
reshape function can be really useful here.
x_splited = x.reshape((-1, a*c))
total = x_splited.mean(axis=1)
This is the answer you need. The reshape function let the first a*c elements in the original matrix become the first row of the new matrix. Then, mean(axis=1) help you get the average of the first row.
Also, you could try something like this:
x_splited = x.reshape((-1, a, c))
You can do something more complicated than this question with it.
Just a tip: in python, it is prefered to avoid using loop because it is slow.
Second tip: if you are still not proficient in using loop in Python, you are encouraged to spend some time to practice it.
I would like to create a step-wise increase in x starting from 0 and increasing by 10 every 30 seconds. I've defined time (t) as t=arange(0,120).
I looked at the Heaviside function but it did not seem to fit my need. I would need my x output to be a single value, not an array.
Sorry if this question is basic or misunderstood - I am very unfamiliar with python.
In order for you to set the value at n[0] to 0.29, n must be an array with something already at position 0.
n = [0.50] #already populated list
n[0] = 0.29
n = [0.29]
Alternatively, you could initialise the list with 0.29 as the first value.
n = [0.29]
n = [0.29]
As for your second question, we could use a for loop
import time #module used for time functions
for x in range(0, 120, 10): #defined a range of x (0,120) with a step of 10
print(x)
time.sleep(30) #wait 30 secs
Do you mean something like this?
import numpy
t=numpy.arange(0,120)
x=numpy.floor(t/30) * 10
It can also be done without numpy using list comprehension.
import math
t=range(0,120)
x=[math.floor(tx/30) * 10 for tx in t]
Or a traditional loop for that matter.
import math
x=[]
t=range(0,120)
for tx in t:
x.append(math.floor(tx/30) * 10)
This is what I have imported:
import random
import matplotlib.pyplot as plt
from math import log, e, ceil, floor
import numpy as np
from numpy import arange,array
import pdb
from random import randint
Here I define the function matrix(p,m)
def matrix(p,m): # A matrix with zeros everywhere, except in every entry in the middle of the row
v = [0]*m
v[(m+1)/2 - 1] = 1
vv = array([v,]*p)
return vv
ct = np.zeros(5) # Here, I choose 5 cause I wanted to work with an example, but should be p in general
Here I define MHops which basically takes the dimensions of the matrix, the matrix and the vector ct and gives me a new matrix mm and a new vector ct
def MHops(p,m,mm,ct):
k = 0
while k < p : # This 'spans' the rows
i = 0
while i < m : # This 'spans' the columns
if mm[k][i] == 0 :
i+=1
else:
R = random.random()
t = -log(1-R,e) # Calculate time of the hopping
ct[k] = ct[k] + t
r = random.random()
if 0 <= r < 0.5 : # particle hops right
if 0 <= i < m-1:
mm[k][i] = 0
mm[k][i+1] = 1
break
else:
break # Because it is at the boundary
else: # particle hops left
if 0 < i <=m-1:
mm[k][i] = 0
mm[k][i-1] = 1
break
else: # Because it is at the boundary
break
break
k+=1
return (mm,ct) # Gives me the new matrix showing the new position of the particles and a new vector of times, showing the times taken by each particle to hop
Now what I wanna do is iterating this process, but I wanna be able to visualize every step in a list. In short what I am doing is:
1. creating a matrix representing a lattice, where 0 means there is no particle in that slot and 1 means there is a particle there.
2. create a function MHops which simulate a random walk of one step and gives me the new matrix and a vector ct which shows the times at which the particles move.
Now I want to have a vector or an array where I have 2*n objects, i.e. the matrix mm and the vector ct for n iterations. I want the in a array, list or something like this cause I need to use them later on.
Here starts my problem:
I create an empty list, I use append to append items at every iteration of the while loop. However the result that I get is a list d with n equal objects coming from the last iteration!
Hence my function for the iteration is the following:
def rep_MHops(n,p,m,mm,ct):
mat = mm
cct = ct
d = []
i = 0
while i < n :
y = MHops(p,m,mat,cct) # Calculate the hop, so y is a tuple y = (mm,ct)
mat = y[0] # I reset mat and cct so that for the next iteration, I go further
cct = y[1]
d.append(mat)
d.append(cct)
i+=1
return d
z = rep_MHops(3,5,5,matrix(5,5),ct) #If you check this, it doesn't work
print z
However it doesn't work, I don't understand why. What I am doing is using MHops, then I want to set the new matrix and the new vector as those in the output of MHops and doing this again. However if you run this code, you will see that v works, i.e. the vector of the times increases and the matrix of the lattice change, however when I append this to d, d is basically a list of n equal objects, where the object are the last iteration.
What is my mistake?
Furthermore if you have any coding advice for this code, they would be more than welcome, I am not sure this is an efficient way.
Just to let you understand better, I would like to use the final vector d in another function where first of all I pick a random time T, then I would basically check every odd entry (every ct) and hence check every entry of every ct and see if these numbers are less than or equal to T. If this happens, then the movement of the particle happened, otherwise it didn't.
From this then I will try to visualize with matpotlibt the result with an histogram or something similar.
Is there anyone who knows how to run this kind of simulation in matlab? Do you think it would be easier?
You're passing and storing by references not copies, so on the next iteration of your loop MHops alters your previously stored version in d. Use import copy; d.append(copy.deepcopy(mat)) to instead store a copy which won't be altered later.
Why?
Python is passing the list by reference, and every loop you're storing a reference to the same matrix object in d.
I had a look through python docs, and the only mention I can find is
"how do i write a function with output parameters (call by reference)".
Here's a simpler example of your code:
def rep_MHops(mat_init):
mat = mat_init
d = []
for i in range(5):
mat = MHops(mat)
d.append(mat)
return d
def MHops(mat):
mat[0] += 1
return mat
mat_init = [10]
z = rep_MHops(mat_init)
print(z)
When run gives:
[[15], [15], [15], [15], [15]]
Python only passes mutable objects (such as lists) by reference. An integer isn't a mutable object, here's a slightly modified version of the above example which operates on a single integer:
def rep_MHops_simple(mat_init):
mat = mat_init
d = []
for i in range(5):
mat = MHops_simple(mat)
d.append(mat)
return d
def MHops_simple(mat):
mat += 1
return mat
z = rep_MHops_simple(mat_init=10)
print(z)
When run gives:
[11, 12, 13, 14, 15]
which is the behaviour you were expecting.
This SO answer How do I pass a variable by reference? explains it very well.
I am attempting to build a simple genetic algorithm that will optimize to an input string, but am having trouble building the [individual x genome] matrix (row n is individual n's genome.) I want to be able to change the population size, mutation rate, and other parameters to study how that affects convergence rate and program efficiency.
This is what I have so far:
import random
import itertools
import numpy as np
def evolve():
goal = 'Hello, World!' #string to optimize towards
ideal = list(goal)
#converting the string into a list of integers
for i in range (0,len(ideal)):
ideal [i] = ord(ideal[i])
print(ideal)
popSize = 10 #population size
genome = len(ideal) #determineing the length of the genome to be the length of the target string
mut = 0.03 #mutation rate
S = 4 #tournament size
best = float("inf") #initial best is very large
maxVal = max(ideal)
minVal = min(ideal)
print (maxVal)
i = 0 #counting variables assigned to solve UnboundLocalError
j = 0
print(maxVal, minVal)
#constructing initial population array (individual x genome)
pop = np.empty([popSize, len(ideal)])
for i, j in itertools.product(range(i), range(j)):
pop[i, j] = [i, random.randint(minVal,maxVal)]
print(pop)
This produces a matrix of the population size with the correct genome length, but the genomes are something like:
[ 6.91364167e-310 6.91364167e-310 1.80613009e-316 1.80613009e-316
5.07224590e-317 0.00000000e+000 6.04100487e+151 3.13149876e-120
1.11787892e+253 1.47872844e-028 7.34486815e+223 1.26594941e-118
7.63858409e+228]
I need them to be random integers corresponding to random ASCII characters .
What am I doing wrong with this method?
Is there a way to make this faster?
I found my current method here:
building an nxn matrix in python numpy, for any n
I found another method that I do not understand, but seems faster and simper, if I can use it here I would like to.
Initialise numpy array of unknown length
Thank you for any assistance you can provide.
Your loop isn't executing because i and j are both 0, so range(i) and range(j) are empty. Also you can't assign a list [i,random] to an array value (np.empty defaults to np.float64). I've simply changed it to only store the random number, but if you really want to store a list, you can change the creation of pop to be pop = np.empty([popSize, len(ideal)],dtype=list)
Otherwise use this for the last lines:
for i, j in itertools.product(range(popSize), range(len(ideal))):
pop[i, j] = random.randint(minVal,maxVal)
Is there a way to "compress" an array in python so as to keep the same range but simply decrease the number of elements to a given value?
For example I have an array with 1000 elements and I want to modify it to have 100. Specifically I have a numpy array that is
x = linspace(-1,1,1000)
But because of the way in which I am using it in my project, I can't simply recreate it using linspace as it will not always be in the domain of -1 to 1 and have 1000 elements. These parameters change and I don't have access to them in the function I am defining. So I need a way to compress the array while keeping the -1 to 1 mapping. Think of it as decreasing the "resolution" of the array. Is this possible with any built in functions or different libraries?
A simple way to "resample" your array is to group it into chunks, then average each chunk:
(Chunking function is from this answer)
# Chunking function
def chunks(l, n):
for i in xrange(0, len(l), n):
yield l[i:i+n]
# Resampling function
def resample(arr, newLength):
chunkSize = len(arr)/newLength
return [np.mean(chunk) for chunk in chunks(arr, chunkSize)]
# Example:
import numpy as np
x = np.linspace(-1,1,15)
y = resample(x, 5)
print y
# Result:
# [-0.85714285714285721, -0.4285714285714286, -3.7007434154171883e-17, 0.42857142857142844, 0.8571428571428571]
As you can see, the range of the resampled array does drift inward, but this effect would be much smaller for larger arrays.
It's not clear to me whether the arrays will always be generated by numpy.linspace or not. If so, there are simpler ways of doing this, like simply picking each nth member of the original array, where n is determined by the "compression" ratio:
def linearResample(arr, newLength):
spacing = len(arr) / newLength
return arr[::spacing]
You could pick items at random to reduce any bias you have in the reduction. If the original sample is unordered it would just be:
import random
sample = range(1000)
def reduce(sample, count):
work = sample[:]
random.shuffle(work)
return work[:count]
If order matters, then use enum to track position and reassemble
def reduce(sample, count):
indexed = [item for item in enumerate(sample)]
random.shuffle(indexed)
trimmed = indexed[:count]
trimmed.sort()
return [item for index,item in trimmed]