Python: Make Copy of List [duplicate] - python

This question already has answers here:
How do I clone a list so that it doesn't change unexpectedly after assignment?
(24 answers)
Closed 6 years ago.
How do I make a copy of a list, so I can edit the copy without affecting the original. Ex:
x = [1., 2., 3., 4.]
y = x
y[0] = 9.
The output is:
x: [9.0, 2.0, 3.0, 4.0]
y: [9.0, 2.0, 3.0, 4.0]
when I want x to be:
x: [1.0, 2.0, 3.0, 4.0]
So how do I make a copy of a variable while keeping the original unchanged?
Thanks in advance,
Eric

Just wrap x with python's list function when declaring y and it works!
x = [1, 2, 3, 4]
y = list(x)
y[0] = 9
print x
print y
#This prints the following
#[1, 2, 3, 4]
#[9, 2, 3, 4]

You can, in this case, use:
x = [1., 2., 3., 4.]
y = x[:]
y[0] = 9.
Output for x and y:
[1.0, 2.0, 3.0, 4.0]
[9.0, 2.0, 3.0, 4.0]
But read this.

Related

How can I reshape a 2D array into 1D in python?

Let me edit my question again. I know how flatten works but I am looking if it possible to remove the inside braces and just simple two outside braces just like in MATLAB and maintain the same shape of (3,4). here it is arrays inside array, and I want to have just one array so I can plot it easily also get the same results is it is in Matlab.
For example I have the following matrix (which is arrays inside array):
s=np.arange(12).reshape(3,4)
print(s)
[[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]]
Is it possible to reshape or flatten() it and get results like this:
[ 0 1 2 3
4 5 6 7
8 9 10 11]
First answer
If I understood correctly your question (and 4 other answers say I didn't), your problem is not how to flatten() or reshape(-1) an array, but how to ensure that even after reshaping, it still display with 4 elements per line.
I don't think you can, strictly speaking. Arrays are just a bunch of elements. They don't contain indication about how we want to see them. That's a printing problem, you are supposed to solve when printing. You can see [here][1] that people who want to do that... start with reshaping array in 2D.
That being said, without creating your own printing function, you can control how numpy display arrays, using np.set_printoptions.
Still, it is tricky so, because this function allows you only to specify how many characters, not elements, are printed per line. So you need to know how many chars each element will need, to force linebreaks.
In your example:
np.set_printoptions(formatter={"all":lambda x:"{:>6}".format(x)}, linewidth=7+(6+2)*4)
The formatter ensure that each number use 6 chars.
The linewidth, taking into account "array([" part, and the closing "])" (9 chars) plus the 2 ", " between each elements, knowing we want 4 elements, must be 9+6×4+2×3: 9 chars for "array([...])", 6×4 for each 4 numbers, 2×3 for each 3 ", " separator. Or 7+(6+2)×4.
You can use it only for one printing
with np.printoptions(formatter={"all":lambda x:"{:>6}".format(x)}, linewidth=7+(6+2)*4):
print(s.reshape(-1))
Edit after some times : subclass
Another method that came to my mind, would be to subclass ndarray, to make it behave as you would want
import numpy as np
class MyArr(np.ndarray):
# To create a new array, with args ls: number of element to print per line, and arr, normal array to take data from
def __new__(cls, ls, arr):
n=np.ndarray.__new__(MyArr, (len(arr,)))
n.ls=ls
n[:]=arr[:]
return n
def __init__(self, *args):
pass
# So that this .ls is viral: when ever the array is created from an operation from an array that has this .ls, the .ls is copyied in the new array
def __array_finalize__(self, obj):
if not hasattr(self, 'ls') and type(obj)==MyArr and hasattr(obj, 'ls'):
self.ls=obj.ls
# Function to print an array with .ls elements per line
def __repr__(self):
# For other than 1D array, just use standard representation
if len(self.shape)!=1:
return super().__repr__()
mxsize=max(len(str(s)) for s in self)
s='['
for i in range(len(self)):
if i%self.ls==0 and i>0:
s+='\n '
s+=f'{{:{mxsize}}}'.format(self[i])
if i+1<len(self): s+=', '
s+=']'
return s
Now you can use this MyArr to build your own 1D array
MyArr(4, range(12))
shows
[ 0.0, 1.0, 2.0, 3.0,
4.0, 5.0, 6.0, 7.0,
8.0, 9.0, 10.0, 11.0]
And you can use it anywhere a 1d ndarray is legal. And most of the time, the .ls attribute will follows (I say "most of the time", because I cannot guarantee that some functions wont build a new ndarray, and fill them with the data from this one)
a=MyArr(4, range(12))
a*2
#[ 0.0, 2.0, 4.0, 6.0,
# 8.0, 10.0, 12.0, 14.0,
# 16.0, 18.0, 20.0, 22.0]
a*a
#[ 0.0, 1.0, 4.0, 9.0,
# 16.0, 25.0, 36.0, 49.0,
# 64.0, 81.0, 100.0, 121.0]
a[8::-1]
#[8.0, 7.0, 6.0, 5.0,
# 4.0, 3.0, 2.0, 1.0,
# 0.0]
# It even resists reshaping
b=a.reshape((3,4))
b
#MyArr([[ 0., 1., 2., 3.],
# [ 4., 5., 6., 7.],
# [ 8., 9., 10., 11.]])
b.reshape((12,))
#[ 0.0, 1.0, 2.0, 3.0,
# 4.0, 5.0, 6.0, 7.0,
# 8.0, 9.0, 10.0, 11.0]
# Or fancy indexing
a[np.array([1,2,5,5,5])]
#[1.0, 2.0, 5.0, 5.0,
# 5.0]
# Or matrix operations
M=np.eye(12,k=1)+2*M.identity(12) # Just a matrix
M#a
#[ 1.0, 4.0, 7.0, 10.0,
# 13.0, 16.0, 19.0, 22.0,
# 25.0, 28.0, 31.0, 22.0]
np.diag(M*a)
#[ 0.0, 2.0, 4.0, 6.0,
# 8.0, 10.0, 12.0, 14.0,
# 16.0, 18.0, 20.0, 22.0]
# But of course, some time you loose the MyArr class
import pandas as pd
pd.DataFrame(a, columns=['v']).v.values
#array([ 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11.])
[1]: https://stackoverflow.com/questions/25991666/how-to-efficiently-output-n-items-per-line-from-numpy-array
Simply, using reshape function with -1 as shape should do:
print(s)
print(s.reshape(-1))
[[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]]
[ 0 1 2 3 4 5 6 7 8 9 10 11]
Try .ravel():
s = np.arange(12).reshape(3, 4)
print(s.ravel())
Prints:
[ 0 1 2 3 4 5 6 7 8 9 10 11]
you can use itertools.chain
from itertools import chain
import numpy as np
s=np.arange(12).reshape(3,4)
print(list(chain(*s)))
# [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
print(s.reshape(12,)) # this will also work
print(s.reshape(s.shape[0] * s.shape[1],)) # if don't know number of elements before hand

Get an array of corresponding values in a reference array from very big input array

I have the following array:
table = np.array([
[1.0, 1.0, 3.0, 5.0],
[1.0, 2.0, 5.0, 3.0],
...
[2.0, 5.0, 2.0, 1.0],
[8.0, 9.0, 7.0, 2.0]])
Let's name the different columns respectively by ['a', 'b', 'm', 'n'].
"table" is my my reference table where I want to extract 'm' and 'n' given 'a' and 'b' contained in a list we will call 'my_list'. In that list, we allow duplicate pairs (a, b).
N.B.: Here list can be referred as array (not in the python sense)
It is easier to do it with for loop. But, for my problem, my list 'my_list' can contain more than 100000 pairs (a, b) so doing it with for loop is not optimal for my work.
How can I do it with numpy functions or pandas functions in a few lines (1 to 3 lines)?
An example of what I want: Given the following list
my_list = np.array([
[1.0, 2.0],
[1.0, 2.0],
[8.0, 9.0]])
I want to have the following result:
results = np.array([
[5.0, 3.0],
[5.0, 3.0],
[7.0, 2.0]])
Thank you in advance
Edit 1: equivalence with for loop
Here is the equivalent with for loop (simplest way with for loop without dichotomous search):
result = []
for x in my_list:
for y in table:
if (x[0] == y[0]) and (x[1] == y[1]):
result.append([y[2], y[3]])
break
print(results)
One possible approach using pandas is to perform inner merge
pd.DataFrame(table).merge(pd.DataFrame(my_list))[[2, 3]].to_numpy()
array([[5., 3.],
[5., 3.],
[7., 2.]])

How to find part of series in some series

The question is simple.
Suppose we have Series with this values:
srs = pd.Series([7.0, 2.0, 1.0, 2.0, 3.0, 5.0, 4.0])
How can I find place (index) of subseries 1.0, 2.0, 3.0?
Using a rolling window we can find the first occurrence of a list a.It puts a 'marker' (e.g. 0, any non-Nan value will be fine) at the end (right border) of the window. Then we use first_valid_index to find the index of this element and correct this value by the window size:
a = [1.0, 2.0, 3.0]
srs.rolling(len(a)).apply(lambda x: 0 if (x == a).all() else np.nan).first_valid_index()-len(a)+1
Output:
2
The simplest solution might be to use list comprehension:
a = srs.tolist() # [7.0, 2.0, 1.0, 2.0, 3.0, 5.0, 4.0]
b = [1.0, 2.0, 3.0]
[x for x in range(len(a)) if a[x:x+len(b)] == b]
# [2]
One naive way is to iterate over the series, subset the n elements and compare if they are equal to the given list:
Here the code:
srs = pd.Series([7.0, 2.0, 1.0, 2.0, 3.0, 5.0, 4.0])
sub_list = [1.0, 2.0, 3.0]
n = len(sub_list)
index_matching = []
for i in range(srs.shape[0] - n + 1):
sub_srs = srs.iloc[i: i+n]
if (sub_srs == sub_list).all():
index_matching.append(sub_srs.index)
print(index_matching)
# [RangeIndex(start=2, stop=5, step=1)]
Or in one line with list comprehension:
out = [srs.iloc[i:i+n].index for i in range(srs.shape[0] - n + 1) if (srs.iloc[i: i+n] == sub_list).all()]
print(out)
# [RangeIndex(start=2, stop=5, step=1)]
If you want an explicit list:
real_values = [[i for i in idx] for idx in out]
print(real_values)
# [[2, 3, 4]]

how can I convert a list containing apostrophe and numbers to numbers (e.g ['2,2.4,3'] to [2,2.4,3]) in python

how can I convert a list containing apostrophe and numbers to numbers (e.g ['2,2.4,3'] to [2,2.4,3]) in Python?
I've tried this:
z = [float(x) if type(x) is str else None for x in ['1 2 3 4']]
You can check first that digit is float or int then convert according to its type():
def flat(lst):
result=[]
for i in lst:
if isinstance(i,str):
for item in i.split(','):
if '.' in item:
result.append(float(item))
else:
result.append(int(item))
return result
print(flat(['2,2.4,3']))
output:
[2, 2.4, 3]
if you want in all in float then:
def flat(lst):
result=[]
for i in lst:
if isinstance(i,str):
for item in i.split(','):
result.append(float(item))
return result
print(flat(['2,2.4,3']))
output:
[2.0, 2.4, 3.0]
l = ['2,2.4,3']
list(map(float,l[0].split(',')))
#[2.0, 2.4, 3.0]
You can use this generic solution:
import itertools
ll = ['2,2.4,3']
list(map(float, itertools.chain(*[str_.split(",") for str_ in ll])))
# [2.0, 2.4, 3.0]
Since you tagged with numpy I'm assuming you are ok with arrays as output. In this case the easiest is using np.fromstring:
x = ['2,2.4,3']
np.fromstring(x[0], sep=',')
# array([ 2. , 2.4, 3. ])
x = ['1 2 3 4']
np.fromstring(x[0], sep=' ')
# array([ 1., 2., 3., 4.])
np.fromstring(x[0], sep=' ', dtype=int)
# array([1, 2, 3, 4])
Apart from that I do recommend you make sure you read and understand #Stefan Pochmann's comment.
If your list always has one string, you could try this:
>>> lst = ['2,2.4,3']
>>> result = [float(x) for x in lst[0].split(',')]
>>> print(result)
[2.0, 2.4, 3.0]
Or if you have multiple strings:
>>> lst = ['2,2.4,3', '2,3.4,5.3']
>>> result = [[float(x) for x in y.split(',')] for y in lst]
>>> print(result)
[[2.0, 2.4, 3.0], [2.0, 3.4, 5.3]]
If you want to flatten the final list:
>>> import itertools
>>> print(list(itertools.chain.from_iterable(result)))
[2.0, 2.4, 3.0, 2.0, 3.4, 5.3]
Try with This:-
a = ['2,2.4,3']
for i in a:
print list(eval(i))

Remove a set of tensors from a tensor in Tensorflow

I'm looking for an easy way to remove a set of tensors from a current tensor in Tensorflow and I'm having a difficult reasonable solution.
For example, let's say that I have the below current tensor:
a = tf.constant([1.0, 2.0, 3.0, 4.0, 5.0, 6.0], shape=[2, 3], name='a')
And that I want to remove, say, two items from this tensor (2.0 and 5.0).
What would be the best way to transform this tensor into [1.0, 3.0, 4.0, 6.0] after it has been created?
Many thanks in advance.
You can call tf.unstack to obtain a list of sub-tensors. Then you can modify the list and call tf.stack to construct a tensor from the list. For example, the following code removes the [2.0, 5.0] column from a:
a = tf.constant([1.0, 2.0, 3.0, 4.0, 5.0, 6.0], shape=[2, 3], name='a')
a_vecs = tf.unstack(a, axis=1)
del a_vecs[1]
a_new = tf.stack(a_vecs, 1)
Another way to do this would be either making use of split or slice function. This would be useful especially if tensor is huge.
Method 1: Making use of split function.
a = tf.constant([1.0, 2.0, 3.0, 4.0, 5.0, 6.0], shape=[2, 3], name='a')
split1, split2, split3 = tf.split(a, [1, 1, 1], 1)
a_new = tf.concat([split1, split3], 1)
Method 2: Making use of slice function.
slice1 = tf.slice(a, [0, 0], [2, 1])
slice2 = tf.slice(a, [0, 2], [2, 1])
a_new = tf.concat([slice1, slice2], 1)
In both the cases, a_new will have
[[ 1. 3.]
[ 4. 6.]]

Categories

Resources