Pythonic way to set variable name as string - python

data1 = [1,2,3,4,5]
data2 = [7,8,9,10,11]
x = data1
y = data2
What I required are the strings of above variable as follows:
xlabel = 'data1'
ylabel = 'data2'
Rather than writing manually, how can I call using x like below:
xlabel = str(x)
But above is wrong.
So, how to do?
xlabel =???
Is there a pythonic way of doing it?

To see why this makes no sense, consider the following snippet
def magic_name_getter(object):
# here be dragons
return the_name
data1 = [1,2,3,4]
magic_name_getter(data1) # returns 'data1'
data1 = [1,2,3,4,5]
data2 = [1,2,3,4,5]
magic_name_getter(data2) # returns 'data2' (..or 'data1'?)
magic_name_getter([7,8,9,10,11]) # returns ... ummm ... ???
Objects in python can have many names, or no names at all.
So what you want, whilst not impossible, is very difficult. Since the variable names are important data for your use case, you should instead be using a dictionary of keys and values mapping the names to the lists so that you have easy access to the names (keys) aswell as the data (values).

You should really consider organizing your data, e.g., in a dictionary:
a = dict(
data1 = [1,2,3,4,5],
data2 = [6,7,8,9,10],
)
x = a.keys()[0]
y = a.keys()[1]
print x, y
Output:
data1 data2
Usually you won't need to store the keys in separate variables like x and y, but work directly on a.keys() or a.items().

collections.namedtuple might help you out:
import collections
Parameters = collections.namedtuple('Parameters', 'dataname, data', verbose = False)
x = Parameters('data1', [1,2,3,4,5])
y = Parameters('data2', [7,8,9,10,11])
>>> x.dataname
'data1'
>>> x.data
[1, 2, 3, 4, 5]
>>> y.dataname
'data2'
>>> y.data
[7, 8, 9, 10, 11]
You would use it for your plot like this:
plt.scatter(x.data, y.data)
plt.xlabel(x.dataname)

Related

Python np where , variable as array index, tuple

I want to search a value in a 2d array and get the value of the correspondent "pair"
in this example i want to search for 'd' and get '14'.
I did try with np location with no success and i finished with this crap code, someone else has a smarter solution?
`
import numpy as np
ar=[[11,'a'],[12,'b'],[13,'c'],[14,'d']]
arr = np.array(ar)
x = np.where(arr == 'd')
print(x)
print("x[0]:"+str(x[0]))
print("x[1]:"+str(x[1]))
a = str(x[0]).replace("[", "")
a = a.replace("]", "")
a = int (a)
print(a)
b = str(x[1]).replace("[", "")
b = b.replace("]", "")
b = int (b) -1
print(b)
print(ar[a][b])
#got 14
`
So you want to lookup a key and get a value?
It feels like you need to use dict!
>>> ar=[[11,'a'],[12,'b'],[13,'c'],[14,'d']]
>>> d = dict([(k,v) for v,k in ar])
>>> d
{'a': 11, 'b': 12, 'c': 13, 'd': 14}
>>> d['d']
14
Use a dict, simple and straight forward:
dct = {k:v for v,k in ar}
dct['d']
If you are hell bent on using np.where, then you can use this:
import numpy as np
ar = np.array([[11,'a'],[12,'b'],[13,'c'],[14,'d']])
i = np.where(ar[:,1] == 'd')[0][0]
result = ar[i, 0]
I didn't know about np.where! It's docstring mentions using nonzero directly, so here's a code snippet that uses that to print the rows that match your requirement: note I add another row with 'd' to show it works for the general case where you want multiple rows matching the condition:
ar=[[11,'a'],[12,'b'],[13,'c'],[14,'d'],[15,'e'],[16,'d']]
arr = np.array(ar)
rows = arr[(arr=='d').nonzero()[0], :]
# array([['14', 'd'],
# ['16', 'd']], dtype='<U21')
This works because nonzero (or where) returns a tuple of row/column indexes of the match. So we just use the first entry in the tuple (an array of row indexes) to index the array row-wise and ask Numpy for all columns (:). This makes the code a bit fragile if you move to 3D or higher dimensions, so beware.
This is assuming you really do intend to use Numpy! Dict is better for many reasons.

How to use a variable inside a str.format() Method? [duplicate]

In order to print a header for tabular data, I'd like to use only one format string line and one spec for column widths w1, w2, w3 (or even w = x, y, z if possible.)
I've looked at this but tabulate etc. don't let me justify things in the column like format does.
This approach works:
head = 'eggs', 'bacon', 'spam'
w1, w2, w3 = 8, 7, 10 # column widths
line = ' {:{ul}>{w1}} {:{ul}>{w2}} {:{ul}>{w3}}'
under = 3 * '='
print line.format(*head, ul='', w1=w1, w2=w2, w3=w3)
print line.format(*under, ul='=', w1=w1, w2=w2, w3=w3)
Must I have individual names as widths {w1}, {w2}, ... in the format string? Attempts like {w[1]}, {w[2]}, give either KeyError or keyword can't be an expression.
Also I think the w1=w1, w2=w2, w3=w3 is not very succinct. Is there a better way?
Using the f-string format becomes very easy nowadays.
If you were using
print(f'{token:10}')
And you want the 10 to be another variable (for example the max length of all the tokens), you would write
print(f'{token:{maxTokenLength}}')
In other words, enclose the variable within {}
In your particular case, all you need is this.
head = 'eggs', 'bacon', 'spam'
w1, w2, w3 = 8, 7, 10 # column widths
print(f' {head[0]:>{w1}} {head[1]:>{w2}} {head[2]:>{w3}}')
print(f' {"="*w1:>{w1}} {"="*w2:>{w2}} {"="*w3:>{w3}}')
Which produces
eggs bacon spam
======== ======= ==========
Specifying w[0], w[1], w[2] should work if you defined w = 8, 7, 10 and passed w as keyword argument like below:
>>> head = 'eggs', 'bacon', 'spam'
>>> w = 8, 7, 10 # <--- list is also okay
>>> line = ' {:{ul}>{w[0]}} {:{ul}>{w[1]}} {:{ul}>{w[2]}}'
>>> under = 3 * '='
>>> print line.format(*head, ul='', w=w) # <-- pass as a keyword argument
eggs bacon spam
>>> print line.format(*under, ul='=', w=w) # <-- pass as a keyword argument
======== ======= ==========
This is jonrsharpe's comment to my OP, worked out so as to visualise what's going on.
line = ' {:{ul}>{w1}} {:{ul}>{w2}} {:{ul}>{w3}}'
under = 3 * '_'
head = 'sausage', 'rat', 'strawberry tart'
# manual dict
v = {'w1': 8, 'w2':5, 'w3': 17}
print line.format(*under, ul='_', **v)
# auto dict
widthl = [8, 7, 9]
x = {'w{}'.format(index): value for index, value in enumerate(widthl, 1)}
print line.format(*under, ul='_', **x)
The point is that I want to be able to quickly rearrange the header without having to tweak the format string. The auto dict meets that requirement very nicely.
As for filling a dict in this way: WOW!

creating a dictionary using a generator with format strings

I would like to create a data frame from a dictionary by looping over a list of string column names, rather than slicing the dataframe directly. For instance
df = pd.DataFrame(np.random.randn(100,7), columns=list('ABCDEFG'))
list_of_cols = ['A','B','C']
dictslice = {'%s': df['%s'] % (elt for elt in list_of_cols), 'Z': np.ones(len(df))}
But I cannot have a format string outside of a string so am not sure how to proceed. I do not want a solution like
df[[list_of_cols]]
since I want to add more vectors to dictslice that may not necessarily be in df.
Can anyone help?
EDIT
I am a fool, it works with this:
dictslice = {'%s' % elt : df[elt] for elt in list_of_cols}
but this does not work:
dictslice = {'%s' % elt : df[elt] for elt in list_of_cols, 'Z': np.ones(len(df))}
This seems like something that can be done with simple variable access.
What's wrong with this:
df = pd.DataFrame(np.random.randn(100,7), columns=list('ABCDEFG'))
list_of_cols = ['A','B','C']
dictslice = dict([(elt, df[elt]) for elt in list_of_cols] + [('Z', np.ones(len(df)))])

python: shuffle list in respect to other attribute

I have two lists and I want to shuffle values in one in respect to the attributes in the other. For example:
list1 = np.array([1,1,1, 2,2,2, 3,3,3]) # spaces for better understanding
list2 = np.array([1,2,3, 4,5,6, 7,8,9])
result = [4,5,6, 1,2,3, 7,8,9]
I solved this problem by
y = split(list2, len(np.unique(list1)))
np.random.shuffle(y)
result = np.array(y).flatten()
I want it to work also for the cases when attributes in list1 are not together. Example:
list1 = np.array([1,2,3,1,2,3,1,2,3])
list2 = np.array([1,2,3,4,5,6,7,8,9])
result = [2,1,3,5,4,6,8,7,9]
Solved it:
uniques = np.unique(list1)
shuffled = uniques.copy()
np.random.shuffle(shuffled)
result = list2.copy()
for orig, new in zip(uniques, shuffled):
result[np.where(list1==orig)] = list2[np.where(list1==new)]

Name of a list changing as I go through a loop

I am trying to make 100 lists with names such as: list1, list2, list3, etc. Essentially what I would like to do is below (although I know it doesn't work I am just not sure why).
num_lists=100
while i < num_lists:
intial_pressure_{}.format(i) = []
centerline_temperature_{}.format(i) = []
And then I want to loop through each list inserting data from a file but I am unsure how I can have the name of the list change in that loop. Since I know this won't work.
while i < num_lists:
initial_pressure_i[0] = value
I'm sure what I'm trying to do is really easy, but my experience with python is only a couple of days. Any help is appreciated.
Thanks
Instead of creating 100 list variables, you can create 100 lists inside of a list. Just do:
list_of_lists = [[] for _ in xrange(100)]
Then, you can access lists on your list by doing:
list_of_lists[0] = some_value # First list
list_of_lists[1] = some_other_value # Second list
# ... and so on
Welcome to Python!
Reading your comments on what you are trying to do, I suggest ditching your current approach. Select an easier data structure to work with.
Suppose you have a list of files:
files = ['data1.txt', 'data2.txt',...,'dataN.txt']
Now you can loop over those files in turn:
data = {}
for file in files:
data[file] = {}
with open(file,'r') as f:
lines=[int(line.strip()) for line in f]
data[file]['temps'] = lines[::2] #even lines just read
data[file]['pressures'] = lines[1::2] #odd lines
Then you will have a dict of dict of lists like so:
{'data1.txt': {'temps': [1, 2, 3,...], 'pressures': [1,2,3,...]},
'data2.txt': {'temps': [x,y,z,...], 'pressures': [...]},
...}
Then you can get your maxes like so:
max(data['data1.txt']['temps'])
Just so you can see what the data will look like, run this:
data = {}
for i in range(100):
item = 'file' + str(i)
data[item] = {}
kind_like_file_of_nums = [float(x) for x in range(10)]
data[item]['temps'] = kind_like_file_of_nums[0::2]
data[item]['pres'] = kind_like_file_of_nums[1::2]
print(data)
You could just make a dictionary of lists. Here's an example found in a similar thread:
>>> from collections import defaultdict
>>> d = defaultdict(list)
>>> for i in a:
... for j in range(int(i), int(i) + 2):
... d[j].append(i)
...
>>> d
defaultdict(<type 'list'>, {1: ['1'], 2: ['1', '2'], 3: ['2']})
>>> d.items()
[(1, ['1']), (2, ['1', '2']), (3, ['2'])]

Categories

Resources