How to write a nested if condition inside a function to return 3 different values to 3 dataframe columns - python-3.x

I am trying to create 3 new columns to my existing dataframe using the logic written on top of other columns in the same dataframe. I have a function which returns 3 values based on specific logic written in it. The function is as below.
def fun(a, b, c, d):
if "Category" in a:
if (b == "some text" or b == "some text 2") and c.str.contains("Status1"):
x = 1
elif (b == "some text 3" or b == "some text 4") and c.str.contains("Status2"):
y = 1
elif b == "some text 5" and c.str.contains("Status3"):
z = 1
else:
if (b == "some text" or b == "some text 2") and c.str.contains("Status1"):
x = 1
x2 = 1
elif (b == "some text 3" or b == "some text 4") and x2 == 0 and c.str.contains("Status2"):
y = 1
elif b == "some text 5" and c.str.contains("Status3"):
z = 1
return x, y, z
Now I want to assign x, y, z to 3 new columns in my dataframe i.e. df['x'], df['y'], df['z'].
I tried to use zip as shown below but it gives an error.
df["x"], df["y"], df["z"] = zip(*df.apply(fun("Col1", "Col2", "Col3", "Col4"), axis=1))
TypeError: ("'tuple' object is not callable", 'occurred at index 0')
Can someone suggest what I am doing wrong here?
The end state for me is to assign x, y and z to 3 new columns in df by performing logical operations on columns in df.

Related

Logic to fill a column in pandas based on some conditions

I'm seeking help to find a good logic on how to add a new column to a Pandas df by applying some conditions.
Column "O" (min_played) will be created based on some conditions:
If a Player is not substituted (replaced), his playtime will be the value from column "G" (time)
If it is substituted (replaced), his playtime will be the value from column "N" (subs)
AND the remaining time will be added to the player with which he was replaced in the same column "O" (min_played)
Example:
Player "Antonio M." from column "J" (name) IS NOT replaced, column "N" (subs) => min_played = time (94.54 = 94.54)
Player "Bowen J." from column "J" (name) IS replaced by "Anderson F."
"Bowen J." min_played = 89 <value taken from column "N" (subs)>
"Anderson F." min_played = 94.54 <value taken from column "G" (time)> minus 89 <value taken from column "N" (subs)> => Total min_played = 5.54
AND this value SHOULD be added to column "min_played" row 13
Why row 13: because his name is present there <column "J" (name) row 13>
For each round <column "B" (tournament_type)> I have to apply this process
Sample Data
# Convert End Time to float
def convert_to_float(x):
remove_char = lambda x: x.replace(' ','').replace(':','.')
temp_list = remove_char(x).split('+')
return sum([float(i) for i in temp_list])
df['time'] = df['time'].apply(convert_to_float)
# Convert Sub-Out Time to Float
def min_played(x):
try:
min_played = x.split(" ")[0].replace("'","")
return convert_to_float(min_played)
except:
pass
df['min_played'] = df['subs'].apply(min_played)
indx = 0
for x in df['status']:
if (x == 'line-up') & (df.loc[indx, 'subs'] is np.nan) == True:
df.loc[indx,'min_played'] = df.loc[indx, 'time']
if (x != 'line-up') & (x != 'sub') == True:
df.loc[indx,'min_played'] = 0
indx += 1
filtr = (df['status'] == 'line-up')
df.loc[filtr, 'sub_min_played'] = df.loc[filtr, 'time'] - df.loc[filtr, 'min_played']
filtr = (df['status'] != 'line-up') & (df['status'] != 'sub')
df.loc[filtr, 'sub_min_played'] = 0
df['name'] = df['name'].apply(lambda x: x.replace(" (C)",""))
df.to_csv('q.csv')
There can be few edge cases in the full data which you need to handle depending on your use case. But this should be goodd starting point.
df = pd.read_csv('SOSample.csv')
def convert_to_float(x):
remove_char = lambda x: x.replace(' ','').replace(':','.')
temp_list = remove_char(x).split('+')
return sum([float(i) for i in temp_list])
df['time'] = df['time'].apply(convert_to_float)
def min_played(time,subs,status):
if status == 'line-up':
if isinstance(subs,str):
t = subs.split("'")[0]
#eval to handle cases like `(90+3)`
# eval("90+3") = 93
return eval(t)
else:
return time
return np.nan
def sub_min_played(time,status,min_played):
if time != min_played:
return time-min_played
df['min_played'] = df.apply(lambda x: min_played(x.time,x.subs,x.status),axis=1)
df['sub_min_played'] = df.apply(lambda x: sub_min_played(x.time,x.status,x.min_played),axis=1)
df
Output:

if-else statement to increment or decrement inside for loop in python

I will take an input n and then print n number of lines.Every line i will input a string if this string is "++X" or "X++" then i will add 1 with 0(The initial value of X is 0). If my string is "--X" or "X--" then i will subtract 1 from 0.(If i already take another string then subtract from this string value).
Here is My code:
n = int(input())
c = 0
for x in range(n):
a = input()
if a == "X++" or "++X":
c = c + 1
elif a == "--X" or "X--":
c = c - 1
print(c)
My input:
2
X++
--X
My output:
2
Expected output:
0
Because,value will 1 for "X++" and 0 again for "--X". So,what is wrong in my code and how can i fix this?
Reference: https://docs.python.org/3/reference/expressions.html#operator-precedence
The order of precedence in the logic expression makes your expression equivalent to if (a == "X++") or "++X": which will always be True because bool("++X") == True. Any non-empty string will be True. So, as other answers suggest, you can use if a == "X++" or a == "++X": since or is evaluated last in the expression, the interp will evaluate the equality operations first, then apply or.
Another more shorthand way to test if a variable has a value that could be a few alternatives is to use the in operator.
n = int(input())
c = 0
for x in range(n):
a = input()
if a in ("X++", "++X"):
c = c + 1
elif a in ("--X", "X--"):
c = c - 1
print(c)
So you had a case where a non-empty string evaluated to True, there are other interesting cases that evaluate to either True or False in expressions. For instance, lists:
li1 = []
li2 = [1, 2]
if li1:
print("li1")
if li2:
print("li2")
Will output li2.
Bonus round - associating values with string input using a dict:
>>> def foo(n):
... d = {'X++': 1, '++X': 1, '--X': -1, 'X--': -1}
... c = 0
... for _ in range(n):
... a = input()
... c += d.get(a, 0)
... return c
...
>>> foo(3)
<-- X++
<-- ++X
<-- ++X
3
n = int(input())
c = 0
for x in range(n):
a = input()
if a == "X++" or a == "++X":
c = c + 1
elif a == "--X" or a == "X--":
c = c - 1
print(c)
:)
Change your condition from
if a == "X++" or "++X":
to
if a == "X++" or a == "++X":
or
if a in ("X++", "++X"):
You forgot to compare with a in every second operand of the ors. A non-empty string will evaluate to True.
n = int(input())
c = 0
for x in range(n):
a = input()
if a == "X++" or a == "++X":
c = c + 1
elif a == "--X" or a == "X--":
c = c - 1
print(c)

Counting weighted average doesn't work properly sometimes

I've made a program that counts weighted average and required weighted value to average being equal to our preference. If I want the average be equal to 85 from (the first value in the list is the weight of next values) [[4,72,78],[3,56],[6,93]] and x value of 6 weight it does not output the right value.
def choice(x):
c = 0
Choice = True
choices = []
while Choice:
if choices == []:
if x != 0:
fill = "weight of required value"
else:
fill = "weight of next values"
else:
if x != 0:
fill = "value of wanted weighted average"
else:
fill = "value"
try:
c = input("Give {}\n" .format(fill))
except:
continue
if isinstance(c, str):
if c == "":
Choice = False
if choices == []:
choices = False
break
else:
try:
choices.append(float(c))
except:
continue
if x != 0 and len(choices) == x:
break
c = 0
return choices
def av(x):
c = 0
alist = x[:]
alist.pop(0)
for a in alist:
c += a*x[0]
return c
def average(k,args):
c = 0
n = 0
for y in range(len(args)):
for a in range(len(args)):
c += (av(args[a]))/2
for b in range(len(args)):
n += (args[b][0]*(len(args[b])-1))/2
if k == 1:
return ([float("{0:.2f}".format(c/n)),c,n])
else:
j = float("{0:.2f}".format(c/n))
print("Weighted average {} from {}" .format(j,args))
def rmark(q,args):
alist = average(1,args)
a = float("{:.2f}" .format((((q[1]*(alist[2]+q[0]))-alist[1])/q[0])))
print("To get weighted average {}, u have to add the value equal to {} of weight {}" .format(q[1],a,q[0]))
# return a
Continue = True
list_choices = []
while Continue:
x = 0
x = choice(0)
if isinstance(x, list):
list_choices.append(x)
elif x == False:
break
print(list_choices)
rmark(choice(2),list_choices)
average(0,list_choices)
Let me break it down for you.
av function is reducing the size of your lists (x1, x2 and x3) to 1 by popping (alist.pop(0)) one element.
Hence, value of len(x1)-1 is 0, which means value of all multipliers in the denominator of (av(x1) + av(x2) + av(x3))/((x1[0]*(len(x1)-1)) + (x2[0]*(len(x2)-1)) + (x3[0]*(len(x3)-1))) is 0. Thus, the error divide by zero.

Prime number generator returns none at the end when inside a function sometimes

I made this prime number generator in python:
for x in range(a , b):
y = 2
while 1 == 1:
if x % y == 0:
if x == y:
print(x)
break
else:
break
y += 1
and it returns all prime numbers up to b as long as a > 2 and b > 3
for example, when a = 2 and b = 11 i get this
2
3
5
7
but when I nest it inside a function like this and print it:
def f(b,a=2):
for x in range(a , b):
y = 2
while 1 == 1:
if x % y == 0:
if x == y:
print(x)
break
else:
break
y += 1
print(f(11))
I get this:
2
3
5
7
None?
Why is it printing a none while inside a function and not without? And how would I fix this?

Code showing no output whatsoever (python)

Trying to make a little Fibonacci game where the user guesses a set amount of steps. I'm trying to make a functioning Fibonacci generator to make the lists to refer to later, but nothing is showing up. I'm sure I'm returning the values. What am I doing wrong?
""" Core Fibonacci Code
a = int(input("How many steps of fibonacci would you like? "))
def fibonacci(counter):
a = 0
b = 1
count = 2
print (a)
print (b)
fib = [0, 1]
while (counter > count):
c = a + b
print (c)
a = b
b = c
count += 1
fibonacci(a)
"""
def fibonacci(counter):
a = 0
b = 1
count = 2
print (a)
print (b)
fib_list.append = a
fib_list.append = b
while (counter > count):
c = a + b
fib_list.append = c
a = b
b = c
count += 1
def homescreen():
print = ("Which gamemode would you like to play?")
print = ("EASY - 10 Steps")
print = ("MEDIUM - 25 Steps")
print = ("HARD - 50 Steps")
request = input("")
if request is "Easy" or "easy":
z = 10
elif request is "Medium" or "medium":
z = 25
elif request is "Hard" or "hard":
z = 50
return z
homescreen()
fibonacci(z)
print (fib_list)
Use print("Which gamemode would you like to play?") and not print=.
You use such format when your returning something from the called function.
eg:
def foo():
#Something
return y
x=foo()
Note :
Use the function append(), dont use lib_list.append=a.
Also declare lib_list outside the function fibonacci() as you're mentioning it in the function call outside of the function.

Resources