Related
Trying to make a simple kinematics array (for fun!) where
You're prompted for an int input tmax that determines t = [0, tmax]
So this would mean that if you input tmax = 5, the time interval would be t = [0, 5] seconds
You're prompted for a float input jerkc (third derivative of position) that determines the constant used in calculation of acceleration (jerkc * t), velocity (jerkc * 1/2 * t^2) and position.
I'm trying to use NumPy (I'm very new to this, and to python) to create a two-dimensional array where:
Row 1: time (so for tmax = 5 this row would be: [0, 1, 2, 3, 4, 5])
Row 2: acceleration(t) (so for tmax = 5, Jerkc = 2 this row would be [0, 2, 4, 6, 8, 10]
Row 3: velocity(t) (so on...)
Row 4: position(t) (so on.....)
I'm still very unfamiliar with lists - and especially NumPy arrays. I'm used to Java arrays, if you're wondering why I'm treating this array the way I am. Here's a sample of what I have so far:
import numpy as np
tmax = int(input('Please enter a timeframe [0, t] [int]: '))
print('Thank you! Your timeframe will be [0, ', tmax, ']!')
jerkc = float(input('Please enter a jerk constant [float]: '))
print('Thank you! Your jerk constant will be ', jerkc, '!')
physics = np.array([[], [], [], []])
t = int(0)
i = int(0)
m = int(0)
e = int(0)
while (t <= tmax):
physics[0, t] = t
t = t + 1
while (i <= tmax):
physics[1, t] = (jerkc * t)
t = t + 1
while (m <= tmax):
physics[2, t] = ((jerkc) * (1/2) * (t ^ 2))
t = t + 1
while (e <= tmax):
physics[3, t] = ((jerkc) * (1/2) * (1/3) * (t ^ 3))
print(physics)
If anyone knows what I'm doing wrong, or can explain to me a way I can use arrays better, please let me know, and please explain yourself carefully and understandably! Thank you!
The special thing about NumPy arrays is that you can do calculations with it. This means that the if you multiply 2 arrays, the result array will contain the values of those arrays multiplied with eachother.
As in this example:
>>> array1=array([1,2,3,4])
>>> array2=array([5,6,7,8])
>>>
>>> array1 * array2
array([ 5, 12, 21, 32])
This does also work for addition, substraction, division...
Another great thing in NumPy is the arange function. It works like the range function in python, but instead returns an array. It has three arguments: start, end and step. The returned array will start with the start argument. The following item will then be added up with the step value, and so on. Untill the next item would be larger then the end value.
Here's an example:
>>> arange(1,10)
array([1, 2, 3, 4, 5, 6, 7, 8, 9])
>>> arange(1,10,2)
array([1, 3, 5, 7, 9])
>>> arange(10)
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
Note: When the step argument is not provided, it is defaulted to 1. If you provide only one argument, it will start from 0 and end with this argument.
There's also a zeros function. It returns an array of the given size, filled with zeros. It is preferrable to initialise arrays in this way.
>>> zeros(10)
array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0.])
>>> zeros((2,2))
array([[0., 0.],
[0., 0.]])
Finally, just as almost all indexable objects in python, NumPy arrays support slicing. It works in the way array[start:end]. It returns the part of the array from index start to index before end. If the start is omitted, the result will be from the start of the array to index end. The same goes for the end argument. If both are omitted (:), the result is just the whole array. Additionally, a third step value can be provided, array[start:end:step]. This does works in the same way as with arange, the indexes of the result values will be counted up from start.
An example:
>>> array1=array([1,2,3,4,5,6,7,8,9,10])
>>>
>>> array1[2:4]
array([3, 4])
>>> array1[:4]
array([1, 2, 3, 4])
>>> array1[2:]
array([ 3, 4, 5, 6, 7, 8, 9, 10])
>>> array1[:]
array([ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
>>> array1[5:9:3] #with step value
array([6, 9])
As NumPy prefers having an index for all the dimensions, we are going to use physics[1,:] to tell NumPy that we want to change all values in the array.
If we would rewrite your code using the previously mentioned things, it would look like:
import numpy as np
tmax = int(input('Please enter a timeframe [0, t] [int]: '))
print('Thank you! Your timeframe will be [0, ', tmax, ']!')
jerkc = float(input('Please enter a jerk constant [float]: '))
print('Thank you! Your jerk constant will be ', jerkc, '!')
physics = np.zeros((4,tmax+1))
physics[0, :] = np.arange(tmax+1)#+1, as the end is not included in the array.
physics[1, :] = physics[0, :] * jerkc
physics[2, :] = ((jerkc) * (1/2) * (physics[0, :] ** 2))
physics[3, :] = ((jerkc) * (1/2) * (1/3) * (physics[0, :] ** 3))
Note: ** is the power operator in python, ^ is exclusive or and thus won't work.
I want to apply calculation only for those values that are higher than threshold. After doing it with boolean indexing, values get rounded. How to prevent it?
starting_score = 1
threshold = 5
x = np.array([0,1,2,3,4,5,6,7,8,9,10])
gt_idx = x > threshold
le_idx = x <= threshold
decay = math.log(2) / 10
y = starting_score * np.exp(-decay * x)
x[gt_idx] = starting_score * np.exp(-decay * x[gt_idx])
y
array([1. , 0.93303299, 0.87055056, 0.8122524 , 0.75785828,
0.70710678, 0.65975396, 0.61557221, 0.57434918, 0.53588673,
0.5 ])
x
array([0, 1, 2, 3, 4, 5, 0, 0, 0, 0, 0])
when applied to full array, I get correct y array.
when applied to part of x, values get selected properly, but rounded to 0
My expected output is
array([0, 1, 2, 3, 4, 5, 0.65975396, 0.61557221, 0.57434918, 0.53588673, 0.5])
It is considered np.int32 as default type for when you create a NumPy array with integers as x. For getting other types in the results you have two ways:
# np.float32 or np.float64
x = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10], dtype=np.float64) # way 1
x = x.astype(np.float64) # way 2
such operation is not needed for y because in is multiplied by a float type value i.e. np.exp(-decay * x), so it became to float types.
numpy automatically assigns the integer data type to x. To preserve your floats you need to change the type of the x array
x.dtype
# Out: dtype('int64')
x = x.astype('float64')
or declare x as an array of float64
x = np.array([0,1,2,3,4,5,6,7,8,9,10], dtype='float64')
I don't understand what squeeze and unsqueeze do to a tensor, even after looking at the docs and related questions.
I tried to understand it by exploring it myself in python. I first created a random tensor with
x = torch.rand(3,2,dtype=torch.float)
>>> x
tensor([[0.3703, 0.9588],
[0.8064, 0.9716],
[0.9585, 0.7860]])
But regardless of how I squeeze it, I end up with the same results:
torch.equal(x.squeeze(0), x.squeeze(1))
>>> True
If I now try to unsqueeze I get the following,
>>> x.unsqueeze(1)
tensor([[[0.3703, 0.9588]],
[[0.8064, 0.9716]],
[[0.9585, 0.7860]]])
>>> x.unsqueeze(0)
tensor([[[0.3703, 0.9588],
[0.8064, 0.9716],
[0.9585, 0.7860]]])
>>> x.unsqueeze(-1)
tensor([[[0.3703],
[0.9588]],
[[0.8064],
[0.9716]],
[[0.9585],
[0.7860]]])
However if I now create a tensor x = torch.tensor([1,2,3,4]), and I try to unsqueeze it then it appears that 1 and -1 makes it a column where as 0 remains the same.
x.unsqueeze(0)
tensor([[1, 2, 3, 4]])
>>> x.unsqueeze(1)
tensor([[1],
[2],
[3],
[4]])
>>> x.unsqueeze(-1)
tensor([[1],
[2],
[3],
[4]])
Can someone provide an explanation of what squeeze and unsqueeze are doing to a tensor? And what's the difference between providing the arguements 0, 1 and -1?
Here is a visual representation of what squeeze/unsqueeze do for an effectively 2d matrix:
When you are unsqueezing a tensor, it is ambiguous which dimension you wish to 'unsqueeze' it across (as a row or column etc). The dim argument dictates this - i.e. position of the new dimension to be added.
Hence the resulting unsqueezed tensors have the same information, but the indices used to access them are different.
Simply put, unsqueeze() "adds" a superficial 1 dimension to tensor (at the specified dimension), while squeeze removes all superficial 1 dimensions from tensor.
You should look at tensor's shape attribute to see it easily. In your last case it would be:
import torch
tensor = torch.tensor([1, 0, 2, 3, 4])
tensor.shape # torch.Size([5])
tensor.unsqueeze(dim=0).shape # [1, 5]
tensor.unsqueeze(dim=1).shape # [5, 1]
It is useful for providing single sample to the network (which requires first dimension to be batch), for images it would be:
# 3 channels, 32 width, 32 height
tensor = torch.randn(3, 32, 32)
# 1 batch, 3 channels, 32 width, 32 height
tensor.unsqueeze(dim=0).shape
unsqueeze can be seen if you create tensor with 1 dimensions, e.g. like this:
# 3 channels, 32 width, 32 height and some 1 unnecessary dimensions
tensor = torch.randn(3, 1, 32, 1, 32, 1)
# 1 batch, 3 channels, 32 width, 32 height again
tensor.squeeze().unsqueeze(0) # [1, 3, 32, 32]
torch.unsqueeze(input, dim) → Tensor
a = torch.randn(4, 4, 4)
torch.unsqueeze(a, 0).size()
>>> torch.Size([1, 4, 4, 4])
a = torch.randn(4, 4, 4)
torch.unsqueeze(a, 1).size()
>>> torch.Size([4, 1, 4, 4])
a = torch.randn(4, 4, 4)
torch.unsqueeze(a, 2).size()
>>> torch.Size([4, 4, 1, 4])
a = torch.randn(4, 4, 4)
torch.unsqueeze(a, 3).size()
>>> torch.Size([4, 4, 4, 1])
torch.squeeze(input, dim=None, out=None) → Tensor
b = torch.randn(4, 1, 4)
>>> tensor([[[ 1.2912, -1.9050, 1.4771, 1.5517]],
[[-0.3359, -0.2381, -0.3590, 0.0406]],
[[-0.2460, -0.2326, 0.4511, 0.7255]],
[[-0.1456, -0.0857, -0.8443, 1.1423]]])
b.size()
>>> torch.Size([4, 1, 4])
c = b.squeeze(1)
b
>>> tensor([[[ 1.2912, -1.9050, 1.4771, 1.5517]],
[[-0.3359, -0.2381, -0.3590, 0.0406]],
[[-0.2460, -0.2326, 0.4511, 0.7255]],
[[-0.1456, -0.0857, -0.8443, 1.1423]]])
b.size()
>>> torch.Size([4, 1, 4])
c
>>> tensor([[ 1.2912, -1.9050, 1.4771, 1.5517],
[-0.3359, -0.2381, -0.3590, 0.0406],
[-0.2460, -0.2326, 0.4511, 0.7255],
[-0.1456, -0.0857, -0.8443, 1.1423]])
c.size()
>>> torch.Size([4, 4])
x_d = np.linspace(-4, 8, 30)
print('x_d shape: ',x_d.shape)
print('x shape: ',x.shape)
density = sum((abs(xi - x_d) < 0.5) for xi in x)---------> difficulty in understanding statement
output:
x_d shape: (30,)
x shape: (20,)
I am having difficulty in understanding above statement
for each value of x we are substracting x_d from it, and we will get single value. But we are density as (30,)
How we got density dimension as (30,)
The expression
xi - x_d
will use NumPy broadcasting to conform the shapes of the two objects. In this case it means treating the scalar value xi as if it was an array of all the same value and of equal dimensions as x_d.
The abs function and the less-than comparison will work element-wise with NumPy arrays, so that the expression
(abs(xi - x_d) < 0.5)
should result in a length-30 array (same size as x_d) where each entry of that array is either True or False depending on the condition applied to each element of x_d.
This gets repeated for multiple values of xi, leading to multiple different length-30 arrays.
The result of calling sum on these arrays is that they are added together elementwise (and also by the luck of broadcasting, since the sum function has a default initial value of 0, the first array is added to 0 elementwise, leaving it unchanged).
So in the final result, it will be a length-30 array, where item 0 of the array counts how many xi values satisfied the absolute value condition based on the 0th element of x_d. Item 1 of the output array will count the number of xi values that satisfied the absolute value condition on the 1st element of x_d, and so on.
Here is an example with some test data:
In [31]: x_d = np.linspace(-4, 8, 30)
In [32]: x = np.arange(20)
In [33]: x
Out[33]:
array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
17, 18, 19])
In [34]: density = sum((abs(xi - x_d) < 0.5) for xi in x)
In [35]: density
Out[35]:
array([0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1])
I have:
import numpy as np
position = np.array([4, 4.34, 4.69, 5.02, 5.3, 5.7, ..., 4])
x = (B/position**2)*dt
A = np.cumsum(x)
assert A[0] == 0 # I want this to be true.
Where B and dt are scalar constants. This is for a numerical integration problem with initial condition of A[0] = 0. Is there a way to set A[0] = 0 and then do a cumsum for everything else?
I don't understand what exactly your problem is, but here are some things you can do to have A[0] = 0.
You can create A to be longer by one index to have the zero as the first entry:
# initialize example data
import numpy as np
B = 1
dt = 1
position = np.array([4, 4.34, 4.69, 5.02, 5.3, 5.7])
# do calculation
A = np.zeros(len(position) + 1)
A[1:] = np.cumsum((B/position**2)*dt)
Result:
A = [ 0. 0.0625 0.11559096 0.16105356 0.20073547 0.23633533 0.26711403]
len(A) == len(position) + 1
Alternatively, you can manipulate the calculation to substract the first entry of the result:
# initialize example data
import numpy as np
B = 1
dt = 1
position = np.array([4, 4.34, 4.69, 5.02, 5.3, 5.7])
# do calculation
A = np.cumsum((B/position**2)*dt)
A = A - A[0]
Result:
[ 0. 0.05309096 0.09855356 0.13823547 0.17383533 0.20461403]
len(A) == len(position)
As you see, the results have different lengths. Is one of them what you expect?
1D cumsum
A wrapper around np.cumsum that sets first element to 0:
def cumsum(pmf):
cdf = np.empty(len(pmf) + 1, dtype=pmf.dtype)
cdf[0] = 0
np.cumsum(pmf, out=cdf[1:])
return cdf
Example usage:
>>> np.arange(1, 11)
array([ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
>>> cumsum(np.arange(1, 11))
array([ 0, 1, 3, 6, 10, 15, 21, 28, 36, 45, 55])
N-D cumsum
A wrapper around np.cumsum that sets first element to 0, and works with N-D arrays:
def cumsum(pmf, axis=None, dtype=None):
if axis is None:
pmf = pmf.reshape(-1)
axis = 0
if dtype is None:
dtype = pmf.dtype
idx = [slice(None)] * pmf.ndim
# Create array with extra element along cumsummed axis.
shape = list(pmf.shape)
shape[axis] += 1
cdf = np.empty(shape, dtype)
# Set first element to 0.
idx[axis] = 0
cdf[tuple(idx)] = 0
# Perform cumsum on remaining elements.
idx[axis] = slice(1, None)
np.cumsum(pmf, axis=axis, dtype=dtype, out=cdf[tuple(idx)])
return cdf
Example usage:
>>> np.arange(1, 11).reshape(2, 5)
array([[ 1, 2, 3, 4, 5],
[ 6, 7, 8, 9, 10]])
>>> cumsum(np.arange(1, 11).reshape(2, 5), axis=-1)
array([[ 0, 1, 3, 6, 10, 15],
[ 0, 6, 13, 21, 30, 40]])
I totally understand your pain, I wonder why Numpy doesn't allow this with np.cumsum. Anyway, though I'm really late and there's already another good answer, I prefer this one a bit more:
np.cumsum(np.pad(array, (1, 0), "constant"))
where array in your case is (B/position**2)*dt. You can change the order of np.pad and np.cumsum as well. I'm just adding a zero to the start of the array and calling np.cumsum.
You can use roll (shift right by 1) and then set the first entry to zero.