Python-How to read and write to a single cell - python

I have an excel file, importing as a dataframe. I want to use python to find matches found in the same row of the dataframe that are no more than 0.0002 difference. The rules are:
Start at column 15/row 1
Compare that value to column 16/row 1. Continue increasing the column number and comparing the new value to column 15/row 1. Loops until either a match is found or reaches the last column (which in my data is 125)
If it finds 2 numbers with a delta no more than 0.0002, it will continue to the next column/row 1 and will see if there is a third number that has a delta no more than 0.0002.
If it finds 3 numbers, then it will continue to the next column to search if there is a fourth number that has a delta no more than 0.0002.
If a fourth match is found and will not continue searching against the starting column. It will now progress to the next starting column (explained below)
If any match is found, it will place the Median of the numbers rounded to 0.0000 (if 2 matches, median of two numbers; if 3 matches median of three numbers; etc.) in a new column to the right of the existing data.
If any match is found, then the starting point (was column 15/1) will now move to column 16/1 and the process will repeat as described above. The goal with continuing is to see if there is another set of numbers that match.
when the starting point column reaches the end, then it goes to the next row.
I am trying to find the right code so I can get the value in row 1 column 1 and then compare it to the other values. Will this work?
df.iat[RowNum, ColNum]
When I find a match, I created four holding columns for each type of match (2, 3, or 4, which means 12 columns). Because each row will have a varying number of matches (or no matches), but for future analysis purposes, I need these to be located in defined column locations to reference. That is why I was planning on have four for each type of match.
For this piece of code, since I know the column name, I was looking to use column name and then use the row number integer to find the right location to enter the value. Is this correct (I concatenate the column name because there are four holding columns for each match end in 1, 2, 3, 4. This is in case there is more than one match found on a row, then I have multiple columns to hold the matches)?
df[ColumnName + str(3)].iloc[RowNum]
I tried to figure out how to get a single 'cell' by using integers (like Cells() in excel, but not sure if right way todo it. The documentation on .loc and .iloc talks about gathering rows of data, not a sincel 'cell'.
Here is a sample of the dataframe (Due to width space, I only showed the first column of each match type (excel TwoMatch2, because that row had 2 times it matched different numbers, but there is four in total for each).
High Low Open Close TwoMatch1 TwoMatch2...ThrMatch1...ForMatch1
0 1.11165 1.11128 1.11137 1.11165 1.1117
1 1.11165 1.11139 1.11148 1.11165
2 1.11167 1.11138 1.11166 1.11138 1.1117 1.1114
3 1.11165 1.11144 1.11165 1.11163 1.1117
4 1.11165 1.11149 1.1115 1.11165
5 1.11165 1.1115 1.11163 1.11163 1.1116 1.1116
6 1.11165 1.11159 1.11159 1.11159 1.1116 1.1116 1.1116
When the code finishes, it write the dataframe back to Excel, csv or database (working on replacing excel and using a database instead). It will have the original data plus the new columns which contain the matches for each row.
Here is the code I have developed, to which I need the above formulas to finalize (in case it helps to know my intentions):
df.reindex(columns = df.columns.tolist() + ['TwoRBs1','TwoRBs2','TwoRBs3','TwoRBs4','ThrRBs1','ThrRBs2','ThrRBs3','ThrRBs4','ForRBs1','ForRBs2','ForRBs3','ForRBs4'])
RowNum = 0
ttlcount = 5
OneMinGroupFlag = 0
FiveMinGroupFlag = 0
FifteenMinGroupFlag = 0
SixtyMinGroupFlag = 0
TwoFortyMinGroupFlag = 0
ColValues = 0
#------------------------------------------------------------------------------------------------------------------------------------------------------------#
#----------------------------------------------------------------Functions-----------------------------------------------------------------------------------#
#------------------------------------------------------------------------------------------------------------------------------------------------------------#
def AssignMinGroup(ColmnNum):
""" If the column or a match was found in the group, then it sets the flag to not check that group again """
nonlocal OneMinGroupFlag
nonlocal FiveMinGroupFlag
nonlocal FifteenMinGroupFlag
nonlocal SixtyMinGroupFlag
nonlocal TwoFortyMinGroupFlag
if (ColmnNum >= 14 and ColmnNum <= 19) or (ColmnNum >= 44 and ColmnNum <= 59): OneMinGroupFlag = 1
elif (ColmnNum >= 20 and ColmnNum <= 25) or (ColmnNum >= 60 and ColmnNum <= 75): FiveMinGroupFlag = 1
elif (ColmnNum >= 26 and ColmnNum <= 31) or (ColmnNum >= 76 and ColmnNum <= 91): FifteenMinGroupFlag = 1
elif (ColmnNum >= 32 and ColmnNum <= 37) or (ColmnNum >= 92 and ColmnNum <= 107): SixtyMinGroupFlag = 1
elif (ColmnNum >= 38 and ColmnNum <= 43) or (ColmnNum >= 108 and ColmnNum <= 123): TwoFortyMinGroupFlag = 1
def FilterGroups(ColmnNum):
nonlocal OneMinGroupFlag
nonlocal FiveMinGroupFlag
nonlocal FifteenMinGroupFlag
nonlocal SixtyMinGroupFlag
nonlocal TwoFortyMinGroupFlag
""""Determines if it is about to test a group that is to be filtered, then sets flag to filter this and go to the next colum/step number"""
if ColmnNum == 44 or ColmnNum == 45 or ColmnNum == 60 or ColmnNum == 61 or ColmnNum == 76 or ColmnNum == 77 or ColmnNum == 92 or ColmnNum == 93 or ColmnNum == 108 or ColmnNum == 109: return(True)
if OneMinGroupFlag == 1 and ((ColmnNum >= 14 and ColmnNum <= 19) or (ColmnNum >= 44 and ColmnNum <= 59)): return(True)
elif FiveMinGroupFlag == 1 and ((ColmnNum >= 20 and ColmnNum <= 25) or (ColmnNum >= 60 and ColmnNum <= 75)): return(True)
elif FifteenMinGroupFlag == 1 and ((ColmnNum >= 26 and ColmnNum <= 31) or (ColmnNum >= 76 and ColmnNum <= 91)): return(True)
elif SixtyMinGroupFlag == 1 and ((ColmnNum >= 32 and ColmnNum <= 37) or (ColmnNum >= 92 and ColmnNum <= 107)): return(True)
elif TwoFortyMinGroupFlag == 1 and ((ColmnNum >= 38 and ColmnNum <= 43) or (ColmnNum >= 108 and ColmnNum <= 123)): return(True)
else: return(False)
def CheckLogMatch(ColumnName,MatchValue):
nonlocal RowNum
""""Will check if the match has already been found, if not, then it will log it into the next available column for match type."""
if abs(df.loc[RowNum, [ColumnName + str(1)]] - MatchValue) <= 0.00029:
if abs(df.loc[RowNum, [ColumnName + str(2)]] - MatchValue) <= 0.00029:
if abs(df.loc[RowNum, [ColumnName + str(3)]] - MatchValue) <= 0.00029:
if abs(df.loc[RowNum, [ColumnName + str(4)]] - MatchValue) <= 0.00029:
pass
else: df.loc[RowNum,[ColumnName + str(4)]] = MatchValue
else: df.loc[RowNum, [ColumnName + str(3)]] = MatchValue
else: df.loc[RowNum,[ColumnName + str(2)]] = MatchValue
else: df.loc[RowNum, [ColumnName + str(1)]] = MatchValue
def Find234Matches():
""""Checks subsequent columns and compares to ColNum to find if there are 2, 3, or 4 matches to ColNum. Then it enters the matches in the table"""
nonlocal ColNum
nonlocal RowNum
nonlocal ColValues
TwoStep = ColNum + 1
while TwoStep <= 123:
if FilterGroups(TwoStep):
TwoStep += 1
continue
else:
Step2Val = df.iat[RowNum, TwoStep]
if abs(ColValues - Step2Val) <= 0.00029:
occur2 = round(median([ColValues, Step2Val]), 4)
AssignMinGroup(TwoStep)
ThreeStep = TwoStep + 1
while ThreeStep <= 123:
if FilterGroups(ThreeStep):
if ThreeStep == 123:
CheckLogMatch('TwoRBs',occur2)
return
else:
ThreeStep += 1
continue
else:
Step3Val = df.iat[RowNum, ThreeStep]
if abs(ColValues - Step3Val) <= 0.00029:
occur3 = round(median([ColValues, Step2Val, Step3Val]), 4)
AssignMinGroup(ThreeStep)
FourStep = ThreeStep + 1
while FourStep <= 123:
if FilterGroups(FourStep):
if FourStep == 123:
CheckLogMatch('ThrRBs',occur3)
CheckLogMatch('TwoRBs',occur2)
return
else:
FourStep += 1
continue
else:
Step4Val = df.iat[RowNum, FourStep]
if abs(ColValues - Step4Val) <= 0.00029:
occur4 = round(median([ColValues, Step2Val, Step3Val, Step4Val]), 4)
CheckLogMatch('ForRBs',occur4)
CheckLogMatch('ThrRBs',occur3)
CheckLogMatch('TwoRBs',occur2)
return
else:
if FourStep == 123:
CheckLogMatch('ThrRBs',occur3)
CheckLogMatch('TwoRBs',occur2)
return
else: FourStep += 1
else:
if ThreeStep == 123:
CheckLogMatch('TwoRBs',occur2)
return
else: ThreeStep += 1
else: TwoStep += 1
#------------------------------------------------------------------------------------------------------------------------------------------------------------#
#------------------------------------------------------------------------------------------------------------------------------------------------------------#
#------------------------------------------------------------------------------------------------------------------------------------------------------------#
while RowNum <= ttlcount:
ColNum = 14
while ColNum <= 107:
ColValues = df.iat[RowNum, ColNum]
if pd.isnull(ColValues) or ColValues > df.iat[RowNum, 9] or ColValues < df.iat[RowNum, 10]:
ColNum += 1
continue
else:
if ColNum == 44 or ColNum == 45 or ColNum == 60 or ColNum == 61 or ColNum == 76 or ColNum == 77 or ColNum == 92 or ColNum == 93 or ColNum == 108 or ColNum == 109:
ColNum += 1
continue
else:
AssignMinGroup(ColNum)
Find234Matches()
ColNum += 1
RowNum += 1

[ answer in progress - working with OP to understand expected output ]
Have look at the output below and determine if this meets your requirements.
(Inferred) Requirements:
Compare each 'High' column to 'Low', 'Open' and 'Close'
Calculate the absolute delta
If <= 0.0002 output the delta into a new column (.e.g 'HighLow')
If > 0.0002, output None
Sample Code:
import numpy as np
import pandas as pd
cols = [('High', i) for i in df.columns[1:]]
for a, b in cols:
df[a+b] = np.where((df[a] - df[b]).abs() <= 0.0002, (df[a] - df[b]).abs(), None)
Output:
High Low Open Close HighLow HighOpen HighClose
0 1.11165 1.11128 1.11137 1.11165 None None 0
1 1.11165 1.11139 1.11148 1.11165 None 0.00017 0
2 1.11167 1.11138 1.11166 1.11138 None 1e-05 None
3 1.11165 1.11144 1.11165 1.11163 None 0 2e-05
4 1.11165 1.11149 1.11150 1.11165 0.00016 0.00015 0
5 1.11165 1.11150 1.11163 1.11163 0.00015 2e-05 2e-05
6 1.11165 1.11159 1.11159 1.11159 6e-05 6e-05 6e-05

I figured it out. The first formula is:
dataframe.iat[RowNumber, ColNumber]
The second one is:
dataframe['ColumnName'].values[RowNum]

Related

How to format file output into specific number of data columns?

I'm just asking a quick question on how to format how numbers are presented in a text file with however many columns I want.
ie.)
1 3 4
2 6 10
3 18 6
As of right now my text file is just writing a new line for ever iteration and I'm having trouble figuring out how to get it to right a new line after 3 iterations of the calculation.
for Number in range(1, 10001):
count = 0
for i in range(2, (Number // 2 + 1)):
if Number % i == 0:
count = count + 1
break
if count == 0 and Number != 1:
file.write(str(Number) + "\n")
You could track the count of numbers written to file, and each multiple of three, write a newline.
output_count = 0
for Number in range(1, 10001):
count = 0
for i in range(2, (Number // 2 + 1)):
if Number % i == 0:
count = count + 1
break
if count == 0 and Number != 1:
file.write(f'{Number} ')
output_count += 1
if output_count % 3 == 0:
file.write("\n")
Code Refactor
It is recommended to refactor the code into functions that tackle pieces of the problem, such as calculating primes versus input/output. For example, in Python 3, you could write the following:
from typing import List
def generate_primes(maximum: int) -> List[int]:
primes = []
for n in range(1, maximum):
count = 0
for i in range(2, (n // 2 + 1)):
if n % i == 0:
count = count + 1
break
if count == 0 and n != 1:
primes.append(n)
return primes
def write_to_file(filename: str, data: List[int], columns: int) -> None:
with open(filename, 'w') as file:
output_count = 0
for n in data:
output_count += 1
if output_count % columns == 0:
file.write(f"{n}\n")
else:
file.write(f"{n} ")
if __name__ == "__main__":
data = generate_primes(10001)
write_to_file("primes.txt", data, columns=3)
Output
2 3 5
7 11 13
17 19 23
29 31 37
41 43 47
53 59 61
67 71 73
79 83 89
...

A test interview question I could not figure out

So I wrote a piece of code in pycharm
to solve this problem:
pick any 5 positive integers that add up to 100
and by addition,subtraction or just using one of the five values
you should be able to make every number up to 100
for example
1,22,2,3,4
for 1 I could give in 1
for 2 i could give in 2
so on
for 21 I could give 22 - 1
for 25 I could give (22 + 2) - 1
li = [1, 1, 1, 1, 1]
lists_of_li_that_pass_T1 = []
while True:
if sum(li) == 100:
list_of_li_that_pass_T1.append(li)
if li[-1] != 100:
li[-1] += 1
else:
li[-1] = 1
if li[-2] != 100:
li[-2] += 1
else:
li[-2] = 1
if li[-3] != 100:
li[-3] += 1
else:
li[-3] = 1
if li[-4] != 100:
li[-4] += 1
else:
li[-4] = 1
if li[-5] != 100:
li[-5] += 1
else:
break
else:
if li[-1] != 100:
li[-1] += 1
else:
li[-1] = 1
if li[-2] != 100:
li[-2] += 1
else:
li[-2] = 1
if li[-3] != 100:
li[-3] += 1
else:
li[-3] = 1
if li[-4] != 100:
li[-4] += 1
else:
li[-4] = 1
if li[-5] != 100:
li[-5] += 1
else:
break
this should give me all the number combinations that add up to 100 out of the total 1*10 ** 10
but its not working please help me fix it so it prints all of the sets of integers
I also can't think of what I would do next to get the perfect sets that solve the problem
After #JohnY comments, I assume that the question is:
Find a set of 5 integers meeting the following requirements:
their sum is 100
any number in the [1, 100] range can be constructed using at most once the elements of the set and only additions and substractions
A brute force way is certainly possible, but proving that any number can be constructed that way would be tedious. But a divide and conquer strategy is possible: to construct all numbers up to n with a set of m numbers u0..., um-1, it is enough to build all numbers up to (n+2)/3 with u0..., um-2 and use um-1 = 2*n/3. Any number in the ((n+2)/3, um-1) range can be written as um-1-x with x in the [1, (n+2)/3] range, and any number in the (um-1, n] range as um-1+y with y in the same low range.
So we can use here u4 = 66 and find a way to build numbers up to 34 with 4 numbers.
Let us iterate: u3 = 24 and build numbers up to 12 with 3 numbers.
One more step u2 = 8 and build numbers up to 4 with 2 numbers.
Ok: u0 = 1 and u1 = 3 give immediately:
1 = u0
2 = 3 - 1 = u1 - u0
3 = u1
4 = 3 + 1 = u1 + u0
Done.
Mathematical disgression:
In fact u0 = 1 and u1 = 3 can build all numbers up to 4, so we can use u2 = 9 to build all numbers up to 9+4 = 13. We can prove easily that the sequence ui = 3i verifies sum(ui for i in [0, m-1]) = 1 + 3 + ... + 3m-1 = (3m - 1)/(3 - 1) = (um - 1) / 2.
So we could use u0=1, u1=3, u2=9, u3=27 to build all numbers up to 40, and finally set u4 = 60.
In fact, u0 and u1 can only be 1 and 3 and u2 can be 8 or 9. Then if u2 == 8, u3 can be in the [22, 25] range, and if u2 == 9, u3 can be in the [21, 27] range. The high limit is given by the 3i sequence, and the low limit is given by the requirement to build numbers up to 12 with 3 numbers, and up to 34 with 4 ones.
No code was used, but I think that way much quicker and less error prone. It is now possible to use Python to show that all numbers up to 100 can be constructed from one of those sets using the divide and conquer strategy.

Creating a function to iterate through DataFrame

I am running into an issue creating a function that will recognize if a particular value in a column is between two values.
def bid(x):
if df['tla'] < 85000:
return 1
elif (df['tla'] >= 85000) & (df['tla'] < 110000):
return 2
elif (df['tla'] >= 111000) & (df['tla'] < 126000):
return 3
elif (df['tla'] >= 126000) & (df['tla'] < 150000):
return 4
elif (df['tla'] >= 150000) & (df['tla'] < 175000):
return 5
elif (df['tla'] >= 175000) & (df['tla'] < 200000):
return 6
elif (df['tla'] >= 200000) & (df['tla'] < 250000):
return 7
elif (df['tla'] >= 250000) & (df['tla'] < 300000):
return 8
elif (df['tla'] >= 300000) & (df['tla'] < 375000):
return 9
elif (df['tla'] >= 375000) & (df['tla'] < 453100):
return 10
elif df['tla'] >= 453100:
return 11
I apply that to my new column:
df['bid_bucket'] = df['bid_bucket'].apply(bid)
And I am getting this error back:
ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().
Anyone have any ideas?
try the following using numpy.select
import numpy as np
values = [1,2,3,4,5,6,7,8,9,10,11]
cond = [df['tla']<85000, (df['tla'] >= 850000) & (df['tla'] < 110000), .... ]
df['bid_bucket'] = np.select(cond, values)
This can already be accomplished with pd.cut, defining the bin edges, and adding +1 to the labels to get your numbering to start at 1.
import pandas as pd
import numpy as np
df = pd.DataFrame({'tla': [7, 85000, 111000, 88888, 51515151]})
df['bid_bucket'] = pd.cut(df.tla, right=False,
bins=[-np.inf, 85000, 110000, 126000, 150000, 175000,
200000, 250000, 300000, 375000, 453100, np.inf],
labels=False)+1
Output: df
tla bid_bucket
0 7 1
1 85000 2
2 111000 3
3 88888 2
4 126000 4
5 51515151 11
You can simply use the np.digitize function to assign the ranges
df['bid_bucket'] = np.digitize(df['bid_bucket'],np.arange(85000,453100,25000))
Example
a = np.random.randint(85000,400000,10)
#array([305628, 134122, 371486, 119856, 321423, 346906, 319321, 165714,360896, 206404])
bins=[-np.inf, 85000, 110000, 126000, 150000, 175000,
200000, 250000, 300000, 375000, 453100, np.inf]
np.digitize(a,bins)
Out:
array([9, 4, 9, 3, 9, 9, 9, 5, 9, 7])
​
​
To keep it in pandas: I think referencing df['tla'] in your function means to reference a series instead of a single value which leads to the ambiguity. You should provide the specific value instead. You could use lambda x, then your code could be something like this
df = pd.DataFrame({'tla':[10,123456,999999]})
def bid(x):
if x < 85000:
return 1
elif (x >= 85000 and x < 110000):
return 2
elif (x >= 111000 and x < 126000):
return 3
elif (x >= 126000 and x < 150000):
return 4
elif (x >= 150000 and x < 175000):
return 5
elif (x >= 175000 and x < 200000):
return 6
elif (x >= 200000 and x < 250000):
return 7
elif (x >= 250000 and x < 300000):
return 8
elif (x >= 300000 and x < 375000):
return 9
elif (x >= 375000 and x < 453100):
return 10
elif x >= 453100:
return 11
df['bid_bucket'] = df['tla'].apply(lambda x: bid(x))
df
You have two possibilities.
Either apply a function defined on a row on the pandas DataFrame in a row-wise way:
def function_on_a_row(row):
if row.tla > ...
...
df.apply(function_on_a_row, axis=1)
In which case keep bid the way you defined it but replace the parameter x with a word like "row" and then the df with "row" to keep the parameters name meaningful, and use:
df.bid_bucket = df.apply(bid, axis=1)
Or apply a function defined on an element on a pandas Series.
def function_on_an_elt(element_of_series):
if element_of_series > ...
...
df.new_column = df.my_column_of_interest.apply(function_on_an_elt)
In your case redefine bid accordingly.
Here you tried to mix both approaches, which does not work.

multiple if else conditions in pandas dataframe and derive multiple columns

I have a dataframe like below.
import pandas as pd
import numpy as np
raw_data = {'student':['A','B','C','D','E'],
'score': [100, 96, 80, 105,156],
'height': [7, 4,9,5,3],
'trigger1' : [84,95,15,78,16],
'trigger2' : [99,110,30,93,31],
'trigger3' : [114,125,45,108,46]}
df2 = pd.DataFrame(raw_data, columns = ['student','score', 'height','trigger1','trigger2','trigger3'])
print(df2)
I need to derive Flag column based on multiple conditions.
i need to compare score and height columns with trigger 1 -3 columns.
Flag Column:
if Score greater than equal trigger 1 and height less than 8 then Red --
if Score greater than equal trigger 2 and height less than 8 then Yellow --
if Score greater than equal trigger 3 and height less than 8 then Orange --
if height greater than 8 then leave it as blank
How to write if else conditions in pandas dataframe and derive columns?
Expected Output
student score height trigger1 trigger2 trigger3 Flag
0 A 100 7 84 99 114 Yellow
1 B 96 4 95 110 125 Red
2 C 80 9 15 30 45 NaN
3 D 105 5 78 93 108 Yellow
4 E 156 3 16 31 46 Orange
For other column Text1 in my original question I have tried this one but the integer columns not converting the string when concatenation using astype(str) any other approach?
def text_df(df):
if (df['trigger1'] <= df['score'] < df['trigger2']) and (df['height'] < 8):
return df['student'] + " score " + df['score'].astype(str) + " greater than " + df['trigger1'].astype(str) + " and less than height 5"
elif (df['trigger2'] <= df['score'] < df['trigger3']) and (df['height'] < 8):
return df['student'] + " score " + df['score'].astype(str) + " greater than " + df['trigger2'].astype(str) + " and less than height 5"
elif (df['trigger3'] <= df['score']) and (df['height'] < 8):
return df['student'] + " score " + df['score'].astype(str) + " greater than " + df['trigger3'].astype(str) + " and less than height 5"
elif (df['height'] > 8):
return np.nan
You need chained comparison using upper and lower bound
def flag_df(df):
if (df['trigger1'] <= df['score'] < df['trigger2']) and (df['height'] < 8):
return 'Red'
elif (df['trigger2'] <= df['score'] < df['trigger3']) and (df['height'] < 8):
return 'Yellow'
elif (df['trigger3'] <= df['score']) and (df['height'] < 8):
return 'Orange'
elif (df['height'] > 8):
return np.nan
df2['Flag'] = df2.apply(flag_df, axis = 1)
student score height trigger1 trigger2 trigger3 Flag
0 A 100 7 84 99 114 Yellow
1 B 96 4 95 110 125 Red
2 C 80 9 15 30 45 NaN
3 D 105 5 78 93 108 Yellow
4 E 156 3 16 31 46 Orange
Note: You can do this with a very nested np.where but I prefer to apply a function for multiple if-else
Edit: answering #Cecilia's questions
what is the returned object is not strings but some calculations, for example, for the first condition, we want to return df['height']*2
Not sure what you tried but you can return a derived value instead of string using
def flag_df(df):
if (df['trigger1'] <= df['score'] < df['trigger2']) and (df['height'] < 8):
return df['height']*2
elif (df['trigger2'] <= df['score'] < df['trigger3']) and (df['height'] < 8):
return df['height']*3
elif (df['trigger3'] <= df['score']) and (df['height'] < 8):
return df['height']*4
elif (df['height'] > 8):
return np.nan
what if there are 'NaN' values in osome columns and I want to use df['xxx'] is None as a condition, the code seems like not working
Again not sure what code did you try but using pandas isnull would do the trick
def flag_df(df):
if pd.isnull(df['height']):
return df['height']
elif (df['trigger1'] <= df['score'] < df['trigger2']) and (df['height'] < 8):
return df['height']*2
elif (df['trigger2'] <= df['score'] < df['trigger3']) and (df['height'] < 8):
return df['height']*3
elif (df['trigger3'] <= df['score']) and (df['height'] < 8):
return df['height']*4
elif (df['height'] > 8):
return np.nan
Here is a way to use numpy.select() for doing this with neat code, scalable and faster:
conditions = [
(df2['trigger1'] <= df2['score']) & (df2['score'] < df2['trigger2']) & (df2['height'] < 8),
(df2['trigger2'] <= df2['score']) & (df2['score'] < df2['trigger3']) & (df2['height'] < 8),
(df2['trigger3'] <= df2['score']) & (df2['height'] < 8),
(df2['height'] > 8)
]
choices = ['Red','Yellow','Orange', np.nan]
df['Flag1'] = np.select(conditions, choices, default=np.nan)
you can use also apply with a custom function on axis 1 like this :
def color_selector(x):
if (x['trigger1'] <= x['score'] < x['trigger2']) and (x['height'] < 8):
return 'Red'
elif (x['trigger2'] <= x['score'] < x['trigger3']) and (x['height'] < 8):
return 'Yellow'
elif (x['trigger3'] <= x['score']) and (x['height'] < 8):
return 'Orange'
elif (x['height'] > 8):
return ''
df2 = df2.assign(flag=df2.apply(color_selector, axis=1))
you will get something like this :

Python for loop breaks text based game

#!/usr/bin/env python
import random
import time
import os
class vars:
running = 1
def win ():
print("You escaped!")
vars.running = 0
time.sleep(4)
return 0
def main ():
char_loc = 11 #The characters current co-ordinates in XY format
pos_char_loc = 11
ex_y = random.randint(1, 5)
ex_x = random.randint(1, 5) * 10
ex_loc = ex_x + ex_y
while vars.running == 1:
os.system('CLS')
x0 = ["#"] * 5
x1 = ["#"] * 5
x2 = ["#"] * 5
x3 = ["#"] * 5
x4 = ["#"] * 5
if (char_loc >= 11 and char_loc <= 55):
if (char_loc >= 11 and char_loc <= 15):
i = 0; k = 11
for x in range(0, 4):
if char_loc == k:
x0.insert(i, '#')
else:
i += 1
k += 1
if (char_loc >= 21 and char_loc <= 25):
i =0; k = 21
for loop1 in range(0, 4):
if char_loc == k:
x1.insert(i, '#')
else:
i += 1
k += 1
if (char_loc >= 31 and char_loc <= 35):
i =0; k = 31
for loop2 in range(0, 4):
if char_loc == k:
x2.insert(i, '#')
else:
i += 1
k += 1
if (char_loc >= 41 and char_loc <= 45):
i =0; k = 41
for loop3 in range(0, 4):
if char_loc == k:
x3.insert(i, '#')
else:
i += 1
k += 1
if (char_loc >= 51 and char_loc <= 55):
i =0; k = 51
for loop5 in range(0, 4):
if char_loc == k:
x4.insert(i, '#')
else:
i += 1
k += 1
else:
print("fail")
print( x0[4],x1[4],x2[4],x3[4],x4[4])
print( x0[3],x1[3],x2[3],x3[3],x4[3])
print( x0[2],x1[2],x2[2],x3[2],x4[2])
print( x0[1],x1[1],x2[1],x3[1],x4[1])
print( x0[0],x1[0],x2[0],x3[0],x4[0])
print(char_loc, ex_loc)
if char_loc == ex_loc:
win()
move = input()
if move == "w" and (char_loc != 15 and char_loc != 25 and char_loc != 35 and char_loc != 45 and char_loc !=55):
char_loc += 1
print("up")
elif move == "s" and (char_loc != 11 and char_loc != 21 and char_loc != 31 and char_loc != 41 and char_loc != 51):
char_loc -= 1
print("down")
elif move == "a" and (char_loc != 11 and char_loc != 12 and char_loc != 13 and char_loc != 14 and char_loc != 15):
char_loc -= 10
print("left")
elif move == "d" and (char_loc != 51 and char_loc != 52 and char_loc != 53 and char_loc != 54 and char_loc != 55):
char_loc += 10
print("right")
else: print("You can't move there!")
if __name__ == '__main__': main()
I'm trying to make a simple text based game where you move the '#' around a grid of '#'s
and try to find the exit. I've changed the code to make it easier for me to make the grid bigger or smaller without adding or deleting huge chunks of code and it keeps on giving me this output:
fail
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
11 52
and I can't figure out what's wrong with it! Only one '#' is supposed to appear :(
I am only a newbie at python so if you have any tips for improving this please, don't hesitate, and post them!
Thanks in advance,
I think the "fail" occurs because it will occur every time the char_loc is not between 51 and 55.
if (char_loc >= 11 and char_loc <= 15):
if (char_loc >= 21 and char_loc <= 25):
if (char_loc >= 31 and char_loc <= 35):
if (char_loc >= 41 and char_loc <= 45):
if (char_loc >= 51 and char_loc <= 55):
else:
What I think you'd want to do here is use elif, which will only fire if the previous checks don't trigger.
if (char_loc >= 11 and char_loc <= 15):
elif (char_loc >= 21 and char_loc <= 25):
elif (char_loc >= 31 and char_loc <= 35):
elif (char_loc >= 41 and char_loc <= 45):
elif (char_loc >= 51 and char_loc <= 55):
else:
In regards to the multiple # symbols, I think this may play a part. Currently you have:
if char_loc == k:
x0.insert(i, '#')
else:
i += 1
k += 1
What I think you're looking to do is:
if char_loc == k:
x0.insert(i, '#')
i += 1
k += 1
Since you want k to change every time that loop iterates.
One last thing that I would suggest is since you have:
i =0; k = 21
i =0; k = 31
i =0; k = 41
i =0; k = 51
You will probably want to add
i =0; k = 11
To the first one.
Hope that helps.

Categories