I'm looking for a way to assign variables dynamically using loop & functions in Python. One way I can do so in R is by using eval(parse(text=text)). For example, assuming I have this code:
var <- c('First','Second','Third')
for (i in 1:length(var)){
text <- paste0("Variable_", var[i], " <- ", i)
eval(parse(text = text))
}
And my desired output is as follow:
> Variable_First
[1] 1
> Variable_Second
[1] 2
> Variable_Third
[1] 3
What is the equivalent way of doing such in Python?
Thanks in advance!
Well, if you really want to do this you can do it in pretty much the same way with exec. Its probably not the best thing to do though...
var = ["First", "Second", "Third"]
for i, j in enumerate(var, start=1):
exec(f"Variable_{j} = i")
Giving
>>> Variable_First
1
>>> Variable_Second
2
>>> Variable_Third
3
Use dictionaries to accomplish something similar: "variable" variables in a restricted namespace. For example, here a dictionary comprehension is used to assign to dictionary dct:
lst = ['First','Second','Third']
dct = {f'Variable_{s}': i for i, s in enumerate(lst)}
print(dct)
# {'Variable_First': 0, 'Variable_Second': 1, 'Variable_Third': 2}
I'm learning about python class. In a toy python script,
class test():
def __init__(self, a, b):
self.new = a
self.old = b
def another_one(self):
temp = self.new
for key in temp.keys():
temp[key] += 1
def old_one(self):
old = self.old
old += 1
a = {'1': 1, '2': 2, '3': 3, '4': 4, '5': 5}
b = 5
test_pass = test(a, b)
test_pass.another_one(), test_pass.old_one()
a, b
I found that by running the method another_one of instance test_pass, dictionary a will be changed. However, integer b will not be altered by running the method old_one.
Why a dictionary will be changed while an integer will not?
Python integers are immutable, you can't change them in-place.
Take a look at the following snippet:
x = 2
print(id(x))
x += 1
print(id(x))
x = [2]
print(id(x))
x += [1]
print(id(x))
You can see that the first part, where the integer is being modified, the unique id() of the object changes. Afterwards x is a completely different object.
When modifying the list, its 'id()' does not change, the list is changes in-place.
The integer is immutable, they can't be magically turn into something different. Lists can.
I have a dataframe having categorical variables. I want to convert them to the numerical using the following logic:
I have 2 lists one contains the distinct categorical values in the column and the second list contains the values for each category. Now i need to map these values in place of those categorical values.
For Eg:
List_A = ['A','B','C','D','E']
List_B = [3,2,1,1,2]
I need to replace A with 3, B with 2, C and D with 1 and E with 2.
Is there any way to do this in Python.
I can do this by applying multiple for loops but I am looking for some easier way or some direct function if there is any.
Any help is very much appreciated, Thanks in Advance.
Create a mapping dict
List_A = ['A','B','C','D','E',]
List_B = [3,2,1,1,2]
d=dict(zip(List_A, List_B))
new_list=['A','B','C','D','E','A','B']
new_mapped_list=[d[v] for v in new_list if v in d]
new_mapped_list
Or define a function and use map
List_A = ['A','B','C','D','E',]
List_B = [3,2,1,1,2]
d=dict(zip(List_A, List_B))
def mapper(value):
if value in d:
return d[value]
return None
new_list=['A','B','C','D','E','A','B']
map(mapper,new_list)
Suppose df is your data frame and "Category" is the name of the column holding your categories:
df[df.Category == "A"] = 3,2, 1, 1, 2
df[(df.Category == "B") | (df.Category == "E") ] = 2
df[(df.Category == "C") | (df.Category == "D") ] = 1
If you only need to replace values in one list with the values of other and the structure is like the one you say. Two list, same lenght and same position, then you only need this:
list_a = []
list_a = list_b
A more convoluted solution would be like this, with a function that will create a dictionary that you can use on other lists:
# we make a function
def convert_list(ls_a,ls_b):
dic_new = {}
for letter,number in zip(ls_a,ls_b):
dic_new[letter] = number
return dic_new
This will make a dictionary with the combinations you need. You pass the two list, then you can use that dictionary on other list:
List_A = ['A','B','C','D','E']
List_B = [3,2,1,1,2]
dic_new = convert_list(ls_a, ls_b)
other_list = ['a','b','c','d']
for _ in other_list:
print(dic_new[_.upper()])
# prints
3
2
1
1
cheers
You could use a solution from machine learning scikit-learn module.
OneHotEncoder
LabelEncoder
http://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.OneHotEncoder.html
http://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.LabelEncoder.html
The pandas "hard" way:
https://stackoverflow.com/a/29330853/9799449
I have a list and from that list every variable uses one index for a value. Example:
val = [2, 4, 8, 6]
var1 = val[0]
var2 = val[1]
var3 = val[2]
var4 = val[3]
Can I put this into a loop somehow? Because I have 20 values so it is long to write 20 variables.
P.S of course, the values from added variables must be usable. And the format I'm using those variables looks like this:
D = {u'label1': var1, u'label2: var2...}
For your specific issue you could use your dict directly from the list
D = {u'label0' : var[0], u'label1' : val[1],...}
and create the dict as
D = dict(("var{}".format(i),v) for i,v in enumerate(val))
Then, you refer to it as values["var1"] for example, where you can put as key the name you like, label_ for instance.
Try it,
label_dict = {}
for i in range(len(val)):
label_dict['label' + str(i+1)] = val[i]
Is there a way to group names together in python, to repeatedly assign to them en masse?
While we can do:
a,b,c = (1,2,3)
I would like to be able to do something like:
names = a,b,c
*names = (3,2,1) # this syntax doesn't work
a,b,c == (3,2,1) #=> True
Is there a built-in syntax for this? If not, I assume it would be possible with an object that overloads its assignment operator. In that case, is there an existing implementation, and would this concept have any unexpected failure modes?
The point is not to use the names as data, but rather to be able to use the actual names as variables that each refer to their own individual item, and to be able to use the list as a list, and to avoid code like:
a = 1
b = 2
c = 3
sequence = (a,b,c)
You should go one level up in your data abstraction. You are not trying to access the entries by their individual names -- you rather use names to denote the whole collection of values, so a simple list might be what you want.
If you want both, a name for the collection and names for the individual items, then a dictionary might be the way to go:
names = "a b c".split()
d = dict(zip(names, (1, 2, 3)))
d.update(zip(names, (3, 2, 1)))
If you need something like this repeatedly, you might want to define a class with the names as attributes:
class X(object):
def __init__(self, a, b, c):
self.update(a, b, c)
def update(self, a, b, c)
self.a, self.b, self.c = a, b, c
x = X(1, 2, 3)
x.update(3, 2, 1)
print x.a, x.b. x.c
This reflects that you want to block a, b and c to some common structure, but keep the option to access them individually by name.
This?
>>> from collections import namedtuple
>>> names = namedtuple( 'names', ['a','b','c'] )
>>> thing= names(3,2,1)
>>> thing.a
3
>>> thing.b
2
>>> thing.c
1
You should use a dict:
>>> d = {"a": 1, "b": 2, "c": 3}
>>> d.update({"a": 8})
>>> print(d)
{"a": 8, "c": 3, "b": 2}
I've realised that "exotic" syntax is probably unnecessary. Instead the following achieves what I wanted: (1) to avoid repeating the names and (2) to capture them as a sequence:
sequence = (a,b,c) = (1,2,3)
Of course, this won't allow:
*names = (3,2,1) # this syntax doesn't work
a,b,c == (3,2,1) #=> True
So, it won't facilitate repeated assignment to the same group of names without writing out those names repeatedly (except in a loop).
Well, you shouldn't do this, since it's potentially unsafe, but you can use the exec statement
>>> names = "a, b, c"
>>> tup = 1,2,3
>>> exec names + "=" + repr(tup)
>>> a, b, c
(1, 2, 3)
Python has such an elegant namespace system:
#!/usr/bin/env python
class GenericContainer(object):
def __init__(self, *args, **kwargs):
self._names = []
self._names.extend(args)
self.set(**kwargs)
def set(self, *args, **kwargs):
for i, value in enumerate(args):
self.__dict__[self._names[i]] = value
for name, value in kwargs.items():
if name not in self._names:
self._names.append(name)
self.__dict__[name] = value
def zip(self, names, values):
self.set(**dict(zip(names, values)))
def main():
x = GenericContainer('a', 'b', 'c')
x.set(1, 2, 3, d=4)
x.a = 10
print (x.a, x.b, x.c, x.d,)
y = GenericContainer(a=1, b=2, c=3)
y.set(3, 2, 1)
print (y.a, y.b, y.c,)
y.set(**dict(zip(('a', 'b', 'c'), (1, 2, 3))))
print (y.a, y.b, y.c,)
names = 'x', 'y', 'z'
y.zip(names, (4, 5, 6))
print (y.x, y.y, y.z,)
if __name__ == '__main__':
main()
Each instance of GenericContainer is an isolated namespace. IMHO it is better than messing with the local namespace even if you are programming under a pure procedural paradigm.
Not sure whether this is what you want...
>>> a,b,c = (1,2,3)
>>> names = (a,b,c)
>>> names
(1, 2, 3)
>>> (a,b,c) == names
True
>>> (a,b,c) == (1,2,3)
True