0

I have a csv file I'm importing as a list

[["df['EPS Rating']>=97"],
 ["df['RS Rating']>=97"],
 ["df['Ind Group RS']<=9"],
 ["df['SMR Rating']<=2"],
 ["df['AD Rating']<=9"],
 ["df['Comp Rating']>=85"],
 ["df['Current Price']>=15"]]

I would like to assign each of these to variables c1 to c7 like this

c1 = df['EPS Rating']>=97
c2 = df['RS Rating']>=97
c3 = df['Ind Group RS']<=9
c4 = df['SMR Rating']<=2
c5 = df['AD Rating']<=9
c6 = df['Comp Rating']>=85
c7 = df['Current Price']>=15

This is so I can use this excellent solution I found by Gecko here also shown below. While this solution is great for readability in my case it ends up being huge as I have more than 30 of these filters and many with more than 20 conditions. How can I assign strings in a list to variables?

something like this maybe?

For i to end_of_list:
    c[i] = [i].value

I hope that explains what I'm trying to do. I'm new to python so I'm still a bit lost. I'm not attached to this idea so if anyone has a better solution I'd love to know it. Thanks

Geckos Original Solution:

import numpy as np
import functools
def conjunction(*conditions):
    return functools.reduce(np.logical_and, conditions)

c_1 = data.col1 == True
c_2 = data.col2 < 64
c_3 = data.col3 != 4

data_filtered = data[conjunction(c1,c2,c3)]
wraith
  • 370
  • 4
  • 16
  • why you need to store into the variables? – Ratnesh Feb 25 '20 at 19:33
  • so that they can be used with the original solution by Gecko – wraith Feb 25 '20 at 19:38
  • 1
    The problem I'm seeing here is that in your situation, you're importing a list of dataframe expressions as strings, and in the solution you posted, the `conjuction` function is being applied to the *evaluation* of those expressions. In your situation, how is the actual DataFrame object computed? – Jon Behnken Feb 25 '20 at 19:49

2 Answers2

1

IIUC, you can just hold each item in a dictionary.

filter_dict = {}
counter = 1
for item in your_list:
    for i in item:
        filter_dict[f'C{counter}'] = i 
        counter += 1

print(filter_dict)

{'C1': "df['EPS Rating']>=97",
 'C2': "df['RS Rating']>=97",
 'C3': "df['Ind Group RS']<=9",
 'C4': "df['SMR Rating']<=2",
 'C5': "df['AD Rating']<=9",
 'C6': "df['Comp Rating']>=85",
 'C7': "df['Current Price']>=15"}

this gives you a string version of your object, you'll have to use eval to use it in your function.

import numpy as np
import functools

def conjunction(*conditions):
    return functools.reduce(np.logical_and, conditions)



df[conjunction([eval(x) for x in filter_dict.values()])

Note, the eval will cause an error if the object doesn't exist in your dataframe.

Umar.H
  • 22,559
  • 7
  • 39
  • 74
  • While I wasn't able to get this to work it actually gave me an idea to fix something else I'm working on, so thank you. – wraith Feb 25 '20 at 20:56
1

Try this:

strings = [["df['EPS Rating']>=97"],
 ["df['RS Rating']>=97"],
 ["df['Ind Group RS']<=9"],
 ["df['SMR Rating']<=2"],
 ["df['AD Rating']<=9"],
 ["df['Comp Rating']>=85"],
 ["df['Current Price']>=15"]]

filters = []
for i in strings:
    filters.append(eval(i[0]))

data_filtered = df[conjunction(*filters)]

You can pass that conjunction function a list as long as you unpack it in place, as done here.

Note: this assumes you have the actual DataFrame object df initialized somewhere in your code prior to running.


Edit: FWIW, this solution would do exactly what you asked for, creating dynamically assigned variables that hold the evaluation of the expression in the string:

for i in range(len(g)):
    x = 'c_{}'.format(i)
    exec('{} = {}'.format(x,g[i][0].strip("\"")))

but instantiating variables this way (with no explicit assignment statement) is generally terrible practice (see link for further information).

Jon Behnken
  • 560
  • 1
  • 3
  • 14
  • This first solution is exactly what I didn't even know I was looking for. It works great. Also thanks for including the second and the link to why that is not a good idea. You're help is greatly appricated. – wraith Feb 25 '20 at 20:58