I am finding it hard to understand Boolean Logic in code - python-3.x

The code below has the Python code with Boolean expressions. Please help me understand the logic in them and how they are bringing out the different results.
#code 1
for row in range(7):#Code to print rows
for col in range(5):#Code to print columns
if ((col == 0 or col == 4) or row!=0):
print("*", end = "")
else:
print(end = " ")
print()
#Code 2
for row in range(7):#Code to print rows
for col in range(5):#Code to print columns
if ((col ==0 and col == 4) and row!=0):
print("*", end = "")
else:
print(end = " ")
print()
#Code 3
for row in range(7):#Code to print rows
for col in range(5):#Code to print columns
if ((col ==0 or col == 4) and row!=0):
print("*", end = "")
else:
print(end = " ")
print()
#code 4
for row in range(7):#Code to print rows
for col in range(5):#Code to print columns
if ((col ==0 and col == 4) or row!=0):
print("*", end = "")
else:
print(end = " ")
print()

The four codes have in common:
Two nested loops go through 7x5 = 35 different cases.
For each case, a Boolean expression is evaluated. Depending on the result, a '*' is printed for true and a gap/space for false.
In English, the four Boolean expressions can be described as follows:
1: ((col == 0 or col == 4) or row!=0)
This is true when either col is 0 or 4, or row is unequal to 0.
In other words: For the first row, there are two '*' columns.
For the remaining six rows, outcome is '*' for all columns
2: ((col == 0 and col == 4) and row!=0)
This can only be true for the last six rows.
But col cannot have two different values at the same time.
Therefore, the expression is always false. It is a contradiction.
3: ((col == 0 or col == 4) and row!=0)
This can only be true for two of the five columns.
It is false for the first row.
4: ((col == 0 and col == 4) or row!=0)
The col part is a contradiction and thus always false.
But the row part is true for the last six rows.
Therefore, one blank rows followed by six rows of '*' are printed

Related

python matrix multiplication check if number of rows of 1st matrix is equal to number of columns of 2nd matrix

I need to perform a matrix multiplication between 2 matrices by taking user input. The below code works fine for the multiplication part but if the no. of rows of 1st matrix are not equal to the no. of columns of the 2nd matrix then it should print NOT POSSIBLE and exit. But it still goes on to add the elements of the matrices. What could possibly be wrong in this code & what could be the solution for the same. Any help would be greatly appreciated
def p_mat(M,row_n,col_n):
for i in range(row_n):
for j in range(col_n):
print(M[i][j],end=" ")
print()
def mat_mul(A_rows,A_cols,A,B_rows,B_cols,B):
if A_cols != B_rows:
print("NOT POSSIBLE")
else:
C = [[0 for i in range(B_cols)] for j in range(A_rows)]
for i in range(A_rows) :
for j in range(B_cols) :
C[i][j] = 0
for k in range(B_rows) :
C[i][j] += A[i][k] * B[k][j]
p_mat(C, A_rows, B_cols)
if __name__== "__main__":
A_rows = int(input("Enter number of rows of 1st matrix: "))
A_cols = int(input("Enter number of columns of 1st matrix: "))
B_rows = int(input("Enter number of rows of 2nd matrix: "))
B_cols = int(input("Enter number of columns of 2nd matrix: "))
##### Initialization of matrix A and B #####
A = [[0 for i in range(B_cols)] for j in range(A_rows)]
B = [[0 for i in range(B_cols)] for j in range(A_rows)]
print("Enter the elements of the 1st matrix: ")
for i in range(A_rows):
for j in range(A_cols):
A[i][j] = int(input("A[" + str(i) + "][" + str(j) + "]: "))
print("Enter the elements of the 2nd matrix: ")
for i in range(B_rows):
for j in range(B_cols):
B[i][j] = int(input("B[" + str(i) + "][" + str(j) + "]:"))
##### Print the 1st & 2nd matrices #####
print("First Matrix : ")
p_mat(A,A_rows,A_cols)
print("Second Matrix : ")
p_mat(B,B_rows,B_cols)
### Function call to multiply the matrices ###
mat_mul(A_rows,A_cols,A,B_rows,B_cols,B)
For matrix multiplication, the number of columns in the first matrix must be equal to the number of rows in the second matrix.
If you want to check the no of rows of 1st matrix and the no. of columns of the 2nd matrix then change the if A_cols != B_rows to if A_rows != B_cols
With your current code, it will print NOT POSSIBLE when A_cols != B_rows which is right.
Ex.
Enter number of rows of 1st matrix: 2
Enter number of columns of 1st matrix: 3
Enter number of rows of 2nd matrix: 2
Enter number of columns of 2nd matrix: 3
Enter the elements of the 1st matrix:
A[0][0]: 1
A[0][1]: 2
A[0][2]: 3
A[1][0]: 4
A[1][1]: 5
A[1][2]: 6
Enter the elements of the 2nd matrix:
B[0][0]:1
B[0][1]:2
B[0][2]:3
B[1][0]:4
B[1][1]:5
B[1][2]:6
First Matrix :
1 2 3
4 5 6
Second Matrix :
1 2 3
4 5 6
NOT POSSIBLE
Another mistake in the code is when you are initialize the Matrices.You are doing
A = [[0 for i in range(B_cols)] for j in range(A_rows)]
B = [[0 for i in range(B_cols)] for j in range(A_rows)]
If the B_cols are smaller than the A_cols when you adding elements in A it will raise IndexError
The same if the B_cols are greater than A_cols when you are adding elements to B will raise IndexError.
Change it to
A = [[0 for i in range(A_cols)] for j in range(A_rows)]
B = [[0 for i in range(B_cols)] for j in range(B_rows)]

pascal number using while loop

I need to print the pascal number
1
1 1
1 2 1
1 3 3 1
etc.
import math
i = 0
j = 1
while j<6:
while i<6:
print(int(math.factorial(5)/(math.factorial(i)*math.factorial(5-i))), end=" ")
i += 1
print(int(math.factorial(j)/(math.factorial(i)*math.factorial(j-i))))
j += 1
it is stated that factorial cannot be negative, although I don't think it is negative.
Take a look at this code, this gives the correct output, even though you can work on making it pretty
n = 5
for j in range(1, n + 1):
row = 1
for i in range(1, j + 1):
print(row)
row = row * (j - i) // i
print(" ")
We know that ith entry in a row of the triange is binomial coefficiant of (j, i) and that all the rows must start with the number 1, and that's why this works. And ofcourse we do integer division.
The for loops can be replace with while loops as you see fit.

Replace values in multiple untitled columns to 0, 1, 2 depending on column

EDITED AS PER COMMENTS
Background: Here is what the current dataframe looks like. The row labels are information texts in original excel file. But I hope this small reproduction of data will be enough for a solution? Actual file has about 100 columns and 200 rows.
Column headers and Row #0 values are repeated with pattern shown below -- except the Sales or Validation text changes at every occurrence of column with an existing title.
One more column before sales with text in each row. Mapping of Xs done for this test. Unfortunately, found no elegant way of displaying text as part of output below.
Sales Unnamed: 2 Unnamed: 3 Validation Unnamed: 5 Unnamed: 6
0 Commented No comment Commented No comment
1 x x
2 x x
3 x x
Expected Output: Replacing the X with 0s, 1s and 2s depending on which column they are in (Commented / No Comment)
Sales Unnamed: 2 Unnamed: 3 Validation Unnamed: 5 Unnamed: 6
0 Commented No comment Commented No comment
1 0 1
2 2 0
3 1 2
Possible Code: I assume the loop would look something like this:
while in row 9:
if column value = "commented":
replace all "x" with 1
elif row 9 when column valkue = "no comment":
replace all "x" with 2
else:
replace all "x" with 0
But being a python novice, I am not sure how to convert this to a working code. I'd appreciate all support and help.
Here is one way to do it:
Define a function to replace the x:
import re
def replaceX(col):
cond = ~((col == "x") | (col == "X"))
# Check if the name of the column is undefined
if not re.match(r'Unnamed: \d+', col.name):
return col.where(cond, 0)
else:
# Check what is the value of the first row
if col.iloc[0] == "Commented":
return col.where(cond, 1)
elif col.iloc[0] == "No comment":
return col.where(cond, 2)
return col
Or if your first row don't contain "Commented" or "No comment" for titled columns you can have a solution without regex:
def replaceX(col):
cond = ~((col == "x") | (col == "X"))
# Check what is the value of the first row
if col.iloc[0] == "Commented":
return col.where(cond, 1)
elif col.iloc[0] == "No comment":
return col.where(cond, 2)
return col.where(cond, 0)
Apply this function on the DataFrame:
# Apply the function on every column (axis not specified so equal 0)
df.apply(lambda col: replaceX(col))
Output:
title Unnamed: 2 Unnamed: 3
0 Commented No comment
1
2 0 2
3 1
Documentation:
Apply: apply a function on every columns/rows depending on the axis
Where: check where a condition is met on a series, if it is not met, replace with value specified.

Selecting rows where a numeric column value change sign through openpyxl

I'm learning Python and openpyxl for data analysis on a large xlsx workbook. I have a for loop that can iterate down an entire column. Here's some example data:
ROW: VALUE:
1 1
2 2
3 3
4 4
5 -4
6 -1
7 -6
8 2
9 3
10 -3
I want to print out the row in which the value changes from positive to negative, and vice versa. So in the above example, row number 5, 8, and 10 would print in the console. How can I use an if statement within a for loop to iterate through a column on openpyxl?
So far I can print all of the cells in a column:
import openpyxl
wb = openpyxl.load_workbook('ngt_log.xlsx')
sheet = wb.get_sheet_by_name('sheet1')
for i in range(1, 10508, 1): # 10508 is the length of the column
print(i, sheet.cell(row=i, column=6).value)
My idea was to just add an if statement inside of the for loop:
for i in range(1, 10508, 1): # 10508 is the length of the column
if(( i > 0 and (i+1) < 0) or (i < 0 and (i+1) > 0)):
print((i+1), sheet.cell(row=i, column=6).value)
But that doesn't work. Am I formulating the if statement correctly?
It looks to me as though your statement is contradicting itself
for i in range(1, 10508, 1): # 10508 is the length of the column
if(( i greater than 0 and (i+1) less than 0) or (i less than 0 and (i+1) greater than
0)):
print((i+1), sheet.cell(row=i, column=6).value)
I wrote the > and < symbols in plain English but if i is greater than 0 then i + 1 is never less than 0 and vise versa so they will never work as both cannot be true
You need to get the sheet.cell values first, and then do the comparisons:
end_range = 10508
for i in range(1, end_range):
current, next = sheet.cell(row=i, column=6).value, sheet.cell(row=i+1, column=6).value
if current > 0 and next < 0 or current < 0 and next > 0:
print(i+1, next)
I am pretty sure there's a sign() function in the math library, but kinda overkill. You may also want to figure out what you want to do if the values are 0.
You can use a flag to check for positive and negative.
ws = wb['sheet1'] # why people persist in using long deprecated syntax is beyond me
flag = None
for row in ws.iter_rows(max_row=10508, min_col=6, max_col=6):
cell = row[0]
sign = cell.value > 0 and "positive" or "negative"
if flag is not None and sign != flag:
print(cell.row)
flag = sign
You can write the rules to select the rows where the sign has changed and put them in a generator expression without using extra memory, like this:
pos = lambda x: x>=0
keep = lambda s, c, i, v: pos(s[c][x].value)!=pos(v.value)
gen = (x+1 for x, y in enumerate(sheet['f']) if x>0 and keep(sheet, 'f', x-1, y))
Then, when you need to know the rows where the sign has changed, you just iterate on gen as below:
for row in gen:
# here you use row

Columns total for categorical data

How do obtain the totals for each of the column (in total 100) in the data frame. My data is a qualitative type.
For example
ID1 ID2 ID3 ID4 ID5 ID100
Y N
Y Y
N N
N Y
And I want to find the total of columns (how many Ys and Ns) in ID1, ID2 and etc....
i have tried typing the following code
colSums(mydata[,[1:ncol(mydata)]
thanks in advance
If you had information about which package you're using for the array I could be more specific. Here's a general solution that assumes your array is a 'list of lists' where each column is a list item within a larger list.
def sum_array(array):
""" Returns the number of Y, N for each column """
for column in array:
y_count = 0
n_count = 0
for cell in column:
if cell == "Y":
y_count += 1
elif cell == "N":
n_count += 1
else:
raise TypeError("bad entry")
# print out count for each column
print "column ", column, " has Y: ", y_count, " and N: ", n_count, " entries."
If you can provide more information, I'll try to help you with a more specific solution.

Resources