How to round a specific selection of numbers in numpy array? - python

From the random numpy list, I want to round only the numbers that are in the index of padInputs. The following code is something that I am trying but doesn't work. What would be a workaround?
padInputs = [0, 2, 7, 8]
random = np.random.rand(13)
for padInput in padInputs:
np.around(random[padInput])
For example,
Input
[0.87720789, 0.88194004, 0.06039337, 0.13874861, 0.85552875]
Output
[0.87720789, 1, 0, 0.13874861, 0.85552875]

Try this way:
random[padInputs] = np.around(random[padInputs])
Note that this will round without decimals, you can pass it as an argument to round in the following way:
random[padInputs] = np.around(random[padInputs], decimals=2)

Problem in your code is you have to assign result back to array as np.around is not in memory function.
like
for padInput in padInputs:
random[padInput] = np.around(random[padInput])
random
array([1. , 0.53206402, 1. , 0.18129529, 0.71238687,
0.92995779, 0.21934659, 0. , 1. , 0.26042076,
0.76826639, 0.82750894, 0.35687544])
but it should be replace by one line as #Bruno define in his answer.

The following one-line piece of code can replace your for loop and does exactly what you want
np.put(random, padInputs, np.around(random))

Related

inverse elements except for zero in a numpy vector

In python, I'm trying to inverse a numpy vector except for these elements with zero values.
I used vectorize function, but always got a wrong answer when the first element is zero, (the code works well when zeros are not in the first position ).
active_N=np.array([0,1,3,5])
f=np.vectorize(lambda x:x if x==0 else 1./x)
active_N_inverse=f(active_N)
Run the code then I get
array([0, 0, 0, 0])
What was wrong with the codes above?
Is there any other method to solve this problem with high efficiency?
Use np.divide with a where clause:
np.divide(1, active_N, where=active_N!=0)
Optionally combined with round:
np.divide(1, active_N, where=active_N!=0).round(100)
Output:
array([0. , 1. , 0.33333333, 0.2 ])

Python numpy how to join numbers from array

I am newbie in Python. I think I'm looking for something easy, but can't find.
I have an numpy binary array, e.g.:
[1,0,1,1,0,0,0,1,1,1,1,0]
And I want to do 2 things:
Join (?) all elements into one number, so result will be:
x=101100011110
Next want to converse it into binary, so:
xx=2846
I have an algorithm to do 2., but I don't know how to do 1. I can do it using loop, but is it possible to do it using numpy, without loop? My array will be huge, so I need the best option.
>>> int(''.join(map(str, [1,0,1,1,0,0,0,1,1,1,1,0])))
101100011110
Or with a little numpy:
>>> int(''.join(np.array([1,0,1,1,0,0,0,1,1,1,1,0]).astype('|S1')))
101100011110
I like #timgeb's answer, but if you're sure you want to use numpy calculations directly, you could do something like this:
x = np.array([1,0,1,1,0,0,0,1,1,1,1,0])
exponents = np.arange(len(x))[::-1]
powers = 10**exponents
result = sum(powers * x)
In [12]: result
Out[12]: 101100011110
As pointed out by #Magellan88 in the comments, if you set powers=2**exponents you can get from 0 to your second part of the question in one sweep.
Since you don't want loop in first task then you can go with map method , I just wanted to show you can also try this :
import numpy as np
array=np.array([1,0,1,1,0,0,0,1,1,1,1,0])
int_con=str(array).replace(',','').replace(' ','').replace('[','').replace(']','')
print("Joined {}".format(int_con))
bin_to_de=0
for digit in int_con:
bin_to_de=bin_to_de*2+int(digit)
print("Decimal conversion {}".format(bin_to_de))
output:
Joined 101100011110
Decimal conversion 2846

String arrays in float arrays without format change

Is there a way to include strings in an array of floats without the format of the array changing such that all floats are changed to strings but the string element is still kept as a string?
eg.
import numpy as np
a = np.array([ 'hi' , 1. , 2. , 3. ])
Ideally I would like the format to remain the same as how it looks when input as 'a' above.
This gives:
array(['hi', '1.0', '2.0', '3.0'], dtype='|S3')
And then how would one save such an array as a text file?
Many thanks,
J
I'm guessing your problem is this: you want to dump out the array np.array([ 'hi' , 1. , 2. , 3. ]) using np.savetxt() but are getting this error:
TypeError: Mismatch between array dtype ('|S3') and format specifier ('%.18e')
If this is the case, you just need to set the fmt kwarg in np.savetxt. Instead of the default %.18e, which is for formatting floating point data, you can use %s, which formats things as a string, even if the original value in the array was numerical.
So this will work:
import numpy as np
a = np.array([ 'hi' , 1. , 2. , 3. ])
np.savetxt("test.out",a,fmt="%s")
Note that you can just do this with the original list - numpy will convert it to an array for you. So for example you can do:
np.savetxt("test.out",[ 'hi' , 1. , 2. , 3. ],fmt="%s")
and it should work fine too.
For the first part of the question, this is not really what numpy arrays are intended for. If you are trying to put different data types into the same array, then you probably want a different data structure. A vanilla python list would do it, but depending on your situation, a dict is probably what you're looking for.
Edit: Based on the comment threads & the specific question, it looks like this is an attempt to make a header on a data file. This can be done directly through
np.savetxt("a.txt",a,header="title goes here")
This can be read directly with np.loadtxt() because by default the header is prepended with #, and by default np.loadtxt() ignores lines that start with #.
Use pickle:
import pickle
a = ['abc',3,4,5,6,7.0]
pickle.dump( a, open( "save.p", "wb" ))
b = pickle.load( open( "save.p", "rb" ) )
print(b)
Output:
['abc', 3, 4, 5, 6, 7.0]

Python: Converting string to floats, reading floats into 2D array, if/then, reordering of rows?

Let me start by saying that I know nothing about Python, but I am trying to learn(mostly through struggling it seems). I've looked around this site and tried to cobble together code to do what I need it to, but I keep running into problems. Firstly, I need to convert a file of 2 columns and 512 rows of strings to floats then put them in a 512x2 array. I check the first column (all rows) for negative values. If negative, add 512. Then I need to reorder the rows in numerical order and write/save the new array.
On to my first problem, converting to floats and putting the floats into an array. I have this code, which I made from others' questions:
with open("binfixtest.composite") as f:
f_values = map(lambda l: l.strip().split(' '), f)
print f_values
newarray = [map(float, v) for v in f_values]
Original format of file:
-91. 0.444253325
-90. 0.883581936
-89. -0.0912338793
New format of f_values:
['-91. 0.444253325'], ['-90. 0.883581936'], ['-89. -0.0912338793']
I'm getting the error:
Traceback (most recent call last):
File "./binfix.py", line 10, in <module>
newarray = [map(float, v) for v in f_values]
ValueError: invalid literal for float(): -91. 0.444253325
which I can't seem to fix. If I don't convert to float, when I try to add 512.0 to negative rows it gives me the error TypeError: cannot concatenate 'str' and 'float' objects
Any help is most definitely appreciated as I am completely clueless here.
If you anticipate having to do tasks like this now and then, I have some suggestions.
Something that will make your life a lot easier is to start learning to use numpy arrays instead of trying to use your own arrays (made up of lists of lists).
For this problem, you can use numpy like this:
>>> import numpy as np
>>> data = np.loadtxt('binfixtest.composite')
>>> data
array([[-91. , 0.44425332],
[-90. , 0.88358194],
[-89. , -0.09123388]])
That's it. Done. Your data is now in a numpy array full of floats.
This works because by default, the numpy.loadtxt method reads line-breaks as row delimiters, and white spaces (including spaces and tabs) as column delimiters, and numbers as floats. There are also a lot of other options for customizing how numpy reads your file if you need them.
Viewing your numpy array
To access row zero, do this:
>>> data[0]
array([-91. , 0.44425332])
To access a value at address 0,0, do this:
>>> data[0,0]
-91.0
To access column zero, do this (the first colon means "all of the rows"):
>>> data[:,0]
array([-91., -90., -89.])
To access a row/column range, do this:
>>> data[1:, :2]
array([[-90. , 0.88358194],
[-89. , -0.09123388]])
The above means "all of the rows start at position 1, and all of the columns until and not including position 2". You can also do thing like 1:3, which would get a total of two rows or columns (3-1=2) starting with position 1.
Changing your numpy array
To change just a single value, do this:
>>> data[0,0] = 1
>>> data[0,0]
1.0
Note that the value we changed at 0,0 has been stored as a float, even though you assigned to an int. This is because a numpy array has ONE data type, and anything you put in that array will try to be converted to that data type:
>>> data.dtype
dtype('float64')
If you want to add 512 to a value at a specific address in the array, you can do this:
>>> data[0,0] = data[0,0] + 512
>>> data[0,0]
421.0
If you want to add 512 to the entire first column, you can do this:
>>> data[:,0] = data[:,0] + 512
>>> data
array([[ 4.21000000e+02, 4.44253325e-01],
[ 4.22000000e+02, 8.83581936e-01],
[ 4.23000000e+02, -9.12338793e-02]])
Useful manipulations for your numpy array
If you want to do a comparison on an array (or a part of one), do that like this (it will return a new array):
>>> data<0
array([[ True, False],
[ True, False],
[ True, True]], dtype=bool)
One way to get only the values in the array that are less than zero is the following (there are other ways):
>>> data*(data<0)
array([[-91. , 0. ],
[-90. , 0. ],
[-89. , -0.09123388]])
This works because in numpy, True values act like 1, and False values act like 0.
And finally, if you want to add 512 to the entire first column only if the value is negative, you can put all of those together and do this:
>>> data[:,0] = (data[:,0]+512)*(data[:,0]<0)
>>> data
array([[ 4.21000000e+02, 4.44253325e-01],
[ 4.22000000e+02, 8.83581936e-01],
[ 4.23000000e+02, -9.12338793e-02]])
Save your array to a new file
If you wish to save the array to a new file, you can use the numpy.savetxt method:
>>> np.savetxt('output.txt', data, fmt = '%.8f', delimiter = ' ', newline = '\n')
The fmt = '%.8f' argument specifies how the float values should be printed (in this case, it will print with 8 decimal places). Consult this part of the docs for more information.
First Part:
#njzk2 is exactly right. Simply removing the literal spaces to change from l.strip().split(' ') to l.strip().split() will correct the error, and you will see the following output for f_values:
[['-91.', '0.444253325'], ['-90.', '0.883581936'], ['-89.', '-0.0912338793']]
And the output for newarray shows float values rather than strings:
[[-91.0, 0.444253325], [-90.0, 0.883581936], [-89.0, -0.0912338793]]
Second Part:
For the second part of the question "if negative, add 512", a simple loop would be clear and simple, and I'm a big believer in clear, readable code.
For example the following is simple and straightforward:
for items in newarray:
if items[0] < 0:
items[0] += 512.00
When we print newarray after the loop, we see the following:
[[421.0, 0.444253325], [422.0, 0.883581936], [423.0, -0.0912338793]]

Selecting data on median value

I want to select one row of an array by the median value in one of the columns.
My method does not work the way I expect it to work, and it could be related to the representation/precision of the value returned by the numpy.median() function.
Here is a minimal working example and a workaround that I found:
import numpy as np
# Create an array with random numbers
some_array = np.random.rand(100)
# Try to select
selection = (some_array == np.median(some_array))
print len(some_array[selection]),len(some_array[~selection]) # Gives: 0, 100 -> selection fails
# Work-around
abs_dist_from_median = np.abs(some_array-np.median(some_array))
selection = (abs_dist_from_median == np.min(abs_dist_from_median))
print len(some_array[selection]),len(some_array[~selection]) # Gives: 1, 99 -> selection succeeded
It seems that the np.median() function returns a different representation off the number, thereby leading to a mismatch in the selection.
I find this behaviour strange, since by definition the median value of an array should be contained in the array. Any help/clarification would be appreciated!
First, the number of values is even such as [1, 2, 3, 4]. the median is (2+3)/2 not 2 or 3. If you change 100 to 101, it works properly. So your second approach is more appropriate on your purpose.
However, the best solution seems to use argsort as
some_array[some_array.argsort()[len(some_array)/2]]
Also, do not use == when you compare two float values. use np.isclose instead.

Categories

Resources