Related
How (in python3) can I extract several n-by-m block from a M-by-N array centering in each element?
for example, In a 9-by-9 matrix, and using a 3-by-3 block, I need to extract the block at each position of the matrix. The challenge here (for me) is because of the I,J element inside of his respective block change of position.
here an image where I show the 9 blocks (for 9 positions) of a 9-by-9 matrix (of course there are 81 blocks to extract)
The code below works perfectly (ONLY) for the corners. Here the size of the block (Wsize-by-Wsize) is a odd number in order to locate the index (Eindex[0],Eindex1) in the middle.
def windowing(array,Wsize,Eindex):
'''
Extract an sub-array of array for the element located in the index 'Eindex'.
Wsize-by-Wsize is the shape of the window
'''
block=np.zeros(tuple(Wsize))
k0 = int((Wsize[0]-1)/2)
k1 = int((Wsize[1]-1)/2)
s0 = Wsize[0]
s1 = Wsize[1]
I = array.shape[0]-1 # las index in i-direction
J = array.shape[1]-1 # las index in i-direction
if (Eindex[0]==0) and (Eindex[1]==0):
block=array[0:Eindex[0]+s0,0:Eindex[1]+s1]
return block
elif (Eindex[0]==I) and (Eindex[1]==0):
block=array[-s0:,0:Eindex[1]+s1]
return block
elif (Eindex[0]==0) and (Eindex[1]==J):
block=array[0:Eindex[0]+s0,-s1:]
return block
elif (Eindex[0]==I) and (Eindex[1]==J):
block=array[-s0:,-s1:]
return block
for example check:
x = np.arange(81).reshape(9,9)
print(windowing(x,[3,3],[0,0]))
print(windowing(x,[3,3],[8,8))
print(windowing(x,[3,3],[8,0]))
print(windowing(x,[3,3],[0,8]))
Here is an approach that takes arbitrary arrays, coordinates and window sizes.
def compute_indices(c, ws, length):
# default setting: % operations to accommodate odd/even window sizes
low, high = c - (ws//2), c + (ws//2) + ws%2
# correction for overlap with borders of array
if low<0:
low, high = 0, ws
elif high>length:
low, high = -ws, None
return low, high
def extract_block(arr, coords, window_size=(3,3)):
# extract array shapes and window sizes into single
# variables
len_r, len_c = arr.shape
wsr, wsc = window_size
# extract coords and correct for 0-indexing
r, c = coords
r0, c0 = r-1, c-1
row_low, row_high = compute_indices(r0, wsr, len_r)
col_low, col_high = compute_indices(c0, wsc, len_c)
return arr[row_low:row_high, col_low:col_high]
test cases:
a = np.arange(81).reshape(9,9)
extract_block(a, [1,1], (3,3))
array[[ 0 1 2]
[ 9 10 11]
[18 19 20]]
extract_block(a, [9,9], (3,3))
array([[60, 61, 62],
[69, 70, 71],
[78, 79, 80]])
extract_block(a, [5,2], (3,6))
array([[27, 28, 29, 30, 31, 32],
[36, 37, 38, 39, 40, 41],
[45, 46, 47, 48, 49, 50]])
You can use numpy like this:
import numpy as np
# Array 9 by 9
x = np.arange(81).reshape((9, 9))
# -1 is important for the indexing
desired_position = np.array([[1,1], [1,5], [1,9], [5,1], [5,5], [5,9], [9,1], [9,5], [9,9]]) - 1
#print(desired_position)
for dp in desired_position:
pos = []
p1, p2 =dp[0] - 1, dp[0] + 2
if p1 <= 0:
p1, p2 = 0, 3
elif p2 >= x.shape[0]:
p2, p1 = x.shape[0], x.shape[0] - 3
pos.append([p1, p2])
p1, p2 = dp[1] - 1, dp[1] + 2
if p1 <= 0:
p1, p2 = 0, 3
elif p2 >= x.shape[1]:
p2, p1 = x.shape[1], x.shape[1] - 3
pos.append([p1, p2])
print(x[pos[0][0]:pos[0][1],pos[1][0]:pos[1][1]])
Please read the docs for numpy for futher information
I edited the code, so now it works.
Edit: Everything is good :)
This is a code which works with small values of t=20 and TR=([[30,20,12,23..],[...]]) but when I put higher values it is shown "Expect x to be a 1-D sorted array_like.". Do you know how to solve this problem??
import matplotlib.pylab as plt
from scipy.special import erfc
from scipy import sqrt
from scipy import exp
import numpy as np
from scipy.interpolate import interp1d
# The function to inverse:
t = 100
alfa = 1.1*10**(-7)
k = 0.18
T1 = 20
Tpow = 180
def F(h):
p = erfc(h*sqrt(alfa*t)/k)
return T1 + (Tpow-T1)*(1-exp((h**2*alfa*t)/k**2)*(p))
# Interpolation
h_eval = np.linspace(-80, 500, 200) # critical step: define the discretization grid
F_inverse = interp1d( F(h_eval), h_eval, kind='cubic', bounds_error=True )
# Some random data:
TR = np.array([[130, 100, 130, 130, 130],
[ 90, 101, 100, 120, 90],
[130, 130, 100, 100, 130],
[120, 101, 120, 90, 110],
[110, 130, 130, 110, 130]])
# Compute the array h for a given array TR
h = F_inverse(TR)
print(h)
# Graph to verify the interpolation
plt.plot(h_eval, F(h_eval), '.-', label='discretized F(h)');
plt.plot(h.ravel(), TR.ravel(), 'or', label='interpolated values')
plt.xlabel('h'); plt.ylabel('F(h) or TR'); plt.legend();
Has anyone an idea how to solve non-linear, implicit equation in numpy.
I have array TR and other values which are included in my equation.
I need to solve it - as a result receive a new array with the same shape
Here is a solution using an 1D interpolation to compute the inverse of the F(h) function. Because non standard root finding method is used, the error is not controlled, and the discretization grid have to be chosen with care. However, the interpolated inverse function can be directly computed over an array.
note: the definition of F is modified, the problem is now Solve h for F(h) = TR
import numpy as np
from scipy.interpolate import interp1d
import matplotlib.pylab as plt
# The function to inverse:
t = 10
alfa = 1.1*10**(-7)
k = 0.18
T1 = 20
Tpow = 100
def F(h):
A = np.exp(h**2*alfa*t/k**2)
B = h**3*2/(3*np.sqrt(3))*(alfa*t)**(3/2)/k**3
return -(Tpow-T1)*( 1 - A + B )
# Interpolation
h_eval = np.linspace(40, 100, 50) # critical step: define the discretization grid
F_inverse = interp1d( F(h_eval), h_eval, kind='cubic', bounds_error=True )
# Some random data:
TR = np.array([[13, 10, 13, 13, 13],
[ 9, 11, 10, 12, 9],
[13, 13, 10, 10, 13],
[12, 11, 12, 9, 11],
[11, 13, 13, 11, 13]])
# Compute the array h for a given array TR
h = F_inverse(TR)
print(h)
# Graph to verify the interpolation
plt.plot(h_eval, F(h_eval), '.-', label='discretized F(h)');
plt.plot(h.ravel(), TR.ravel(), 'or', label='interpolated values')
plt.xlabel('h'); plt.ylabel('F(h) or TR'); plt.legend();
With the other function, the following lines are changed:
from scipy.special import erf
def F(h):
return (Tpow-T1)*(1-np.exp((h**2*alfa*t)/k**2)*(1.0-erf(h*np.sqrt(alfa*t)/k)))
# Interpolation
h_eval = np.linspace(15, 35, 50) # the range is changed
I want to sum over a certain, but rolling, period within my dynamic model. The formal representation is as follows
A simple code snippet to run the equation is:
import numpy as np
import pandas as pd
import operator
year = np.arange(50)
m_ = [50, 30, 15]
a = [25, 15, 7.5]
ARC_ = [38, 255, 837]
r = 0.03
I tried subtracting list a from m_ by list(map(operator.sub, m_, a))) as found within another post.
My failed attempt looks something like this:
for t in year:
for i in range(0, 3):
while t < t+(list(map(operator.sub, m_, a))):
L_[t] = sum(ARC_[i] / (1+r) ** t)
Not at all sure that I understood it right, I tried to base my answer on the equation. Even if it is still a bit of from the result you expect, it might help you to solve your issue.
I create a result list to store each value of L[t], i.e. 50 values. Then I compute the start / stop of the sum for every couple (t,i) and compute it.
import numpy as np
years = np.arange(50)
m_ = [50, 30, 15]
a = [25, 15, 7.5]
ARC_ = [38, 255, 837]
r = 0.03
result = []
for t in years:
s = 0
for i in range(3):
t0 = t
tf = t + m_[i]-a[i]
for k in range(int(t0), int(tf+1)):
s += ARC_[i] / (1+r) ** t
result.append(s)
If what you wanted to do is to compute the difference element-wise between m and a, a simple solution is:
[m_[i] - a[i] for i in range(len(m_))]
Hope it helps.
I have a list of numbers:
[10,20,30]
What I need is to expand it according to a predefined increment. Thus, let's call x the increment and x=2, my result should be:
[10,12,14,16,18,20,22,24,.....,38]
Right now I am using a for loop, but it is very slow and I am wondering if there is a faster way.
EDIT:
newA = []
for n in array:
newA= newA+ generateNewNumbers(n, p, t)
The function generates new number simply generate the new numbers to add to the list.
EDIT2:
To better define the problem the first array contains some timestamps:
[10,20,30]
I have two parameters one is the sampling rate and one is the sampling time, what I need is to expand the array adding between two timestamps the correct number of timestamps, according to the sampling rate.
For example, if I have a sampling rate 3 and a sampling time 3 the result should be:
[10,13,16,19,20,23,26,29,30,33,36,39]
You can add the same set of increments to each time stamp using np.add.outer and then flatten the result using ravel.
import numpy as np
a = [10,20,35]
inc = 3
ninc = 4
np.add.outer(a, inc * np.arange(ninc)).ravel()
# array([10, 13, 16, 19, 20, 23, 26, 29, 35, 38, 41, 44])
You can use list comprhensions but I'm not sure if I understand the stopping condition for the last point inclusion
a = [10, 20, 30, 40]
t = 3
sum([[x for x in range(y, z, t)] for y, z in zip(a[:-1], a[1:])], []) + [a[-1]]
will give
[10, 13, 16, 19, 20, 23, 26, 29, 30, 33, 36, 39, 40]
Using range and itertools.chain
l = [10,20,30]
x = 3
from itertools import chain
list(chain(*[range(i,i+10,x) for i in l]))
#Output:
#[10, 13, 16, 19, 20, 23, 26, 29, 30, 33, 36, 39]
Here is a bunch of good answers already. But I would advise numpy and linear interpolation.
# Now, this will give you the desired result with your first specifications
# And in pure Python too
t = [10, 20, 30]
increment = 2
last = int(round(t[-1]+((t[-1]-t[-2])/float(increment))-1)) # Value of last number in array
# Note if you insist on mathematically "incorrect" endpoint, do:
#last = ((t[-1]+(t[-1]-t[-2])) -((t[-1]-t[-2])/float(increment)))+1
newt = range(t[0], last+1, increment)
# And, of course, this may skip entered values (increment = 3
# But what you should do instead, when you use the samplerate is
# to use linear interpolation
# If you resample the original signal,
# Then you resample the time too
# And don't expand over the existing time
# Because the time doesn't change if you resampled the original properly
# You only get more or less samples at different time points
# But it lasts the same length of time.
# If you do what you originally meant, you actually shift your datapoints in time
# Which is wrong.
import numpy
t = [10, 20, 30, 40, 50, 60]
oldfs = 4000 # 4 KHz samplerate
newfs = 8000 # 8 KHz sample rate (2 times bigger signal and its time axis)
ratio = max(oldfs*1.0, newfs*1.0)/min(newfs, oldfs)
newlen = round(len(t)*ratio)
numpy.interp(
numpy.linspace(0.0, 1.0, newlen),
numpy.linspace(0.0, 1.0, len(t)),
t)
This code can resample your original signal too (if you have one). If you just want to cram in some more timepoints in between, you can also use interpolation. Again, don't go over the existing time. Although this code does it, to be compatible with the first one. And so that you can get ideas on what you can do.
t = [10, 20, 30]
increment = 2
last = t[-1]+((t[-1]-t[-2])/float(increment))-1 # Value of last number in array
t.append(last)
newlen = (t[-1]-t[0])/float(increment)+1 # How many samples we will get in the end
ratio = newlen / len(t)
numpy.interp(
numpy.linspace(0.0, 1.0, newlen),
numpy.linspace(0.0, 1.0, len(t)),
t)
This though results in an increment of 2.5 instead of 2. But it can be corrected. The thing is that this approach would work on floating time points as well as on integers. And fast. It will slow down if there is a lot of them, but until you reach some great number of them it will work pretty fast.
I have performed mean-shift segmentation on an image and got the labels array, where each point value corresponds to the segment it belongs to.
labels = [[0,0,0,0,1],
[2,2,1,1,1],
[0,0,2,2,1]]
On the other hand, I have the corresponding grayScale image, and want to perform operations on each regions independently.
img = [[100,110,105,100,84],
[ 40, 42, 81, 78,83],
[105,103, 45, 52,88]]
Let's say, I want the sum of the grayscale values for each region, and if it's <200, I want to set those points to 0 (in this case, all the points in region 2), How would I do that with numpy? I'm sure there's a better way than the implementation I have started, which includes many, many for loops and temporary variables...
Look into numpy.bincount and numpy.where, that should get you started. For example:
import numpy as np
labels = np.array([[0,0,0,0,1],
[2,2,1,1,1],
[0,0,2,2,1]])
img = np.array([[100,110,105,100,84],
[ 40, 42, 81, 78,83],
[105,103, 45, 52,88]])
# Sum the regions by label:
sums = np.bincount(labels.ravel(), img.ravel())
# Create new image by applying threhold
final = np.where(sums[labels] < 200, -1, img)
print final
# [[100 110 105 100 84]
# [ -1 -1 81 78 83]
# [105 103 -1 -1 88]]
You're looking for the numpy function where. Here's how you get started:
import numpy as np
labels = [[0,0,0,0,1],
[2,2,1,1,1],
[0,0,2,2,1]]
img = [[100,110,105,100,84],
[ 40, 42, 81, 78,83],
[105,103, 45, 52,88]]
# to sum pixels with a label 0:
px_sum = np.sum(img[np.where(labels == 0)])