Есть и другие способы получить list2
, которые лучше подходили бы для этой проблемы. Это решение основано исключительно на ваших переменных:
1. Простой метод (Bruteforce):
list2 = ['goat=3','duck=2']
dict2 = dict(item.split('=') for item in list2)
comparison_func = {'>': lambda x,y: x > y,
'<': lambda x,y: x < y,
'=': lambda x,y: x == y}
valid_rows = []
for row_ix, row_contents in df.iterrows():
conditions_met = True
for condition in row_contents:
for operator in comparison_func:
if operator in condition:
animal, value = condition.split(operator)
break
is_true = comparison_func[operator]
if not is_true(int(dict2.get(animal,0)), int(value)):
conditions_met = False
break
if conditions_met:
valid_rows.append(row_ix)
print(valid_rows)
Выход:
[0]
Позже вы можете сделать:
>>> df['conditions_met'] = df.index.isin(valid_rows)
>>> df
condition1 Condition2 Condition3 Condition4 conditions_met
0 duck>1 goat>2 sheep=0 chicken=0 True
1 duck=0 chicken=0 donkey>1 zebra>0 False
2. Умный метод:
>>> list2 = ['goat=3','duck=2']
>>> dict2 = dict(item.split('=') for item in list2)
>>> globals().update(dict2)
>>> def is_true(x):
... if '>' in x:
... animal, value = x.split('>')
... return int(globals().get(animal, 0)) > int(value)
... elif '<' in x:
... animal, value = x.split('<')
... return int(globals().get(animal, 0)) < int(value)
... else:
... animal, value = x.split('=')
... return int(globals().get(animal, 0)) == int(value)
>>> df.applymap(is_true)
condition1 Condition2 Condition3 Condition4
0 True True True True
1 False True False False
>>> df[df.applymap(is_true).all(1)].index
Int64Index([0], dtype='int64')
>>> df['conditions_met'] = df.applymap(is_true).all(1)
>>> df
condition1 Condition2 Condition3 Condition4 conditions_met
0 duck>1 goat>2 sheep=0 chicken=0 True
1 duck=0 chicken=0 donkey>1 zebra>0 False
ОБЪЯСНЕНИЕ для метода 1 :
# make a dict out of list2, there are other ways
# to get to the next step directly from list1
dict2 = dict(item.split('=') for item in list2)
# make a mapping of checker functions wrt operators
comparison_func = {'>': lambda x,y: x > y,
'<': lambda x,y: x < y,
'=': lambda x,y: x == y}
# create an empty list to keep provision for the case
# when conditions are matched in multiple rows
valid_rows = []
# Iterate over the dataframe
for row_ix, row_contents in df.iterrows():
# set a flag for each row
conditions_met = True
# iterate through each column in the row
for condition in row_contents:
# check which operator is in the current column
for operator in comparison_func:
# if operator found, split by it, store the (animal, value) and break
if operator in condition:
animal, value = condition.split(operator)
break
# get the comparison function for the operator, name the function is_true
is_true = comparison_func[operator]
# check if the function evaluates to true with given values
# dict2.get(animal,0) will give the value for that animal from dict2
# if the animal is not in dict2 it will return default value 0
if not is_true(int(dict2.get(animal,0)), int(value)):
# if condition did not meet, set conditions_met False, break
conditions_met = False
break
# outside the loop, if the conditions_met stays True throughout the previous loop
# append the row index to the valid_rows
if conditions_met:
valid_rows.append(row_ix)
print(valid_rows)
Объяснение для метода 2 :
globals()
- это встроенная функция python, которая предоставляет доступ к глобальным переменным в пространстве имен через словарь. Здесь я обновляю пространство имен global
с помощью dict2
, т.е. теперь и goat
, и duck
существуют как глобальные переменные, и к ним можно обращаться из других функций для сравнения.
df.applymap(func)
применяет функцию к каждому элементу информационного кадра.
df.all(axis)
проверяет, все ли значения оцениваются как True
для данного axis
.
И это все.