Tuesday 22 March 2022

Python Visualizing λ

λ +

Python compact coding is very much possible with lambda function.

Anonymous function.. Function without name. 

# lambda arguments : expression

# using Lambda
result = lambda x,y : x + y
# print(result(5,5))

# otherwise by function
def add(x,y):
return (x+y)
add(5,5)

sorted() takes elements from the list and sort the elements. Please see how key is implemented using lambda function. This can be used for any list with numbers, strings, list of lists. For simple understanding, number list is given. keys are defined using lambda arguments.


# Difference Between function and lambda -anonymous function
def cube(x):
return (x*x*x)

lambda_cube = lambda x: x*x*x

print(cube(125))
print((lambda_cube(25))) # No function call or return

list_of_tuples = [(1, 2, 3, 4), (4, -3, 2, 1), (3, 4, -1, 2), (2, 3, 4, -1)]
list_of_tuples_sorted = sorted(list_of_tuples)
print(list_of_tuples_sorted)
"""
[(1, 2, 3, 4), (2, 3, 4, -1), (3, 4, -1, 2), (4, -3, 2, 1)]
"""

list_of_tuples_sorted = sorted(list_of_tuples, key =lambda x: x[1]) # Sort in second element of all tuples
print(list_of_tuples_sorted)
"""
[(4, -3, 2, 1), (1, 2, 3, 4), (2, 3, 4, -1), (3, 4, -1, 2)]
"""

list_of_tuples_sorted = sorted(list_of_tuples, key =lambda x: x[3]) # Sort in last element of all tuples
print(list_of_tuples_sorted)

"""
[(2, 3, 4, -1), (4, -3, 2, 1), (3, 4, -1, 2), (1, 2, 3, 4)] """
Map function is used to pass the arguments from the list. Literally mapping values..
# Using function map()
alist = [1, 2, 3, 4, 5]
mlist =
map(lambda x : x*x, alist) # map supplies elements instead of one element
print(list(mlist)) # [1, 4, 9, 16, 25]

# Otherwise using c-omprehensive list
clist = [x * x for x in alist]
print(clist) # [1, 4, 9, 16, 25]
#Using Filter to find even numbers in the list
flist = filter(lambda x: x%2 == 0, alist)
print(list(flist)) # [2, 4]

# Otherwise using c-omprehensive list
clist = [x for x in alist if x%2== 0]
print(clist) # [2, 4]
#Using reduce ....please import reduce from functools

def my_add(a, b):
   result = a + b
print(f"{a} + {b} = {result}")
return result

from functools import reduce
numbers = [0, 1, 2, 3, 4]
print(reduce(my_add, numbers))

# Note passing a,b and see the cumulative sum is first
element in the next iteration

0 + 1 = 1
1 + 2 = 3
3 + 3 = 6
6 + 4 = 10
10
"""
import functools

# list definition
alist = [1, 2, 7, 4, 5, 6, 3, ]

# educe to compute sum of list
print("The sum of the list elements is : ", end="")
print(functools.reduce(lambda a, b: a + b, alist)) #28

# reduce to compute maximum element from list
print("The maximum element of the list is : ", end="")
print(functools.reduce(lambda a, b: a if a > b else b, alist)) # 7

To understand the visualization the above reduce code execution: please click the  link https://pythontutor.com/visualize.html#mode=display Paste the above code in the editor window. Click visualize execution and next button. 

Step 1:


Step 2: Delete the first line (if any) as shown in the above screen shot. 
Paste the copied code as shown below


Step 3: Click Visualize Button to see the screen shot similar to the following one:


Step 4: Click Next Button to see the following 



Please note global frame with functools points with arrow to  objects module instance by arrow.

Step 5: Click Next button again to see as shown below



Notice the pointer from alist  1,2,7,4,5.  

Step 5: Click again to see the window similar to one shown below:



Please note the print out box in top right : First print out put 
'The sum of the list elements is seen  :'

Step 6:  Again Click Next  to see the window as shown below.


In this screen shot, please notice  lambda list with a =1 ,b=2 . Press Clicks to see the screen below to see the return value 3:



Step 7:.. Click Next many times until that button is disabled  to see execution until you get results 
The maximum element of the list is : 7  as shown in the screen below.


This is the video showing the execution.


Hope, you understand the execution of the python code. 

Hey, you know how to write concise coding using Lambda.. If you don't, sorry, God only save you!!!!😇

Happy Learning with AMET, ODL


Pandas#02

 PANDAS .... (Analysing)

# Analyzing Data Frames
print(df.info())
"""
Int64Index: 169 entries, 0 to 168
Data columns (total 4 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 Duration 169 non-null int64
1 Pulse 169 non-null int64
2 Maxpulse 169 non-null int64
3 Calories 164 non-null float64
dtypes: float64(1), int64(3)
memory usage: 6.6 KB
None
"""

The info() method also tells 

  • Non-Null values there are present in each column, (164 of 169 Non-Null values in the "Calories" column.) . 
  • 5 rows with no value at all, in the "Calories" column, for whatever reason.
  • Empty values, or Null values, can be bad when analyzing data, duplicate values and 
  • Removing rows with empty values  called cleaning data, and you will learn more about that in the next chapters.
Let us dive in to the code for cleaning. Assume the data file as dirtydata.csv


import pandas as pd
df = pd.read_csv('dirtydata.csv') # reading dirty
# print(df)
"""
Duration Date Pulse Maxpulse Calories
0 60 '2020/12/01' 110 130 409.1
1 60 '2020/12/02' 117 145 479.0
2 60 '2020/12/03' 103 135 340.0
3 45 '2020/12/04' 109 175 282.4
4 45 '2020/12/05' 117 148 406.0
5 60 '2020/12/06' 102 127 300.0
6 60 '2020/12/07' 110 136 374.0
7 450 '2020/12/08' 104 134 253.3
8 30 '2020/12/09' 109 133 195.1
9 60 '2020/12/10' 98 124 269.0
10 60 '2020/12/11' 103 147 329.3
11 60 '2020/12/12' 100 120 250.7
12 60 '2020/12/12' 100 120 250.7
13 60 '2020/12/13' 106 128 345.3
14 60 '2020/12/14' 104 132 379.3
15 60 '2020/12/15' 98 123 275.0
16 60 '2020/12/16' 98 120 215.2
17 60 '2020/12/17' 100 120 300.0
18 45 '2020/12/18' 90 112 NaN
19 60 '2020/12/19' 103 123 323.0
20 45 '2020/12/20' 97 125 243.0
21 60 '2020/12/21' 108 131 364.2
22 45 NaN 100 119 282.0
23 60 '2020/12/23' 130 101 300.0
24 45 '2020/12/24' 105 132 246.0
25 60 '2020/12/25' 102 126 334.5
26 60 20201226 100 120 250.0
27 60 '2020/12/27' 92 118 241.0
28 60 '2020/12/28' 103 132 NaN
29 60 '2020/12/29' 100 132 280.0
30 60 '2020/12/30' 102 129 380.3
31 60 '2020/12/31' 92 115 243.0
"""
print(df.info)
"""
<bound method DataFrame.info of Duration Date Pulse Maxpulse Calories
0 60 '2020/12/01' 110 130 409.1
1 60 '2020/12/02' 117 145 479.0
2 60 '2020/12/03' 103 135 340.0
3 45 '2020/12/04' 109 175 282.4
4 45 '2020/12/05' 117 148 406.0
5 60 '2020/12/06' 102 127 300.0
6 60 '2020/12/07' 110 136 374.0
7 450 '2020/12/08' 104 134 253.3
8 30 '2020/12/09' 109 133 195.1
9 60 '2020/12/10' 98 124 269.0
10 60 '2020/12/11' 103 147 329.3
11 60 '2020/12/12' 100 120 250.7
12 60 '2020/12/12' 100 120 250.7
13 60 '2020/12/13' 106 128 345.3
14 60 '2020/12/14' 104 132 379.3
15 60 '2020/12/15' 98 123 275.0
16 60 '2020/12/16' 98 120 215.2
17 60 '2020/12/17' 100 120 300.0
19 60 '2020/12/19' 103 123 323.0
20 45 '2020/12/20' 97 125 243.0
21 60 '2020/12/21' 108 131 364.2
23 60 '2020/12/23' 130 101 300.0
24 45 '2020/12/24' 105 132 246.0
25 60 '2020/12/25' 102 126 334.5
26 60 20201226 100 120 250.0
27 60 '2020/12/27' 92 118 241.0
29 60 '2020/12/29' 100 132 280.0
30 60 '2020/12/30' 102 129 380.3
31 60 '2020/12/31' 92 115 243.0>
"""
df.dropna(inplace = True)
# print(df.to_string())
print(df) # check no values are dropped
"""
Duration Date Pulse Maxpulse Calories
0 60 '2020/12/01' 110 130 409.1
1 60 '2020/12/02' 117 145 479.0
2 60 '2020/12/03' 103 135 340.0
3 45 '2020/12/04' 109 175 282.4
4 45 '2020/12/05' 117 148 406.0
5 60 '2020/12/06' 102 127 300.0
6 60 '2020/12/07' 110 136 374.0
7 450 '2020/12/08' 104 134 253.3
8 30 '2020/12/09' 109 133 195.1
9 60 '2020/12/10' 98 124 269.0
10 60 '2020/12/11' 103 147 329.3
11 60 '2020/12/12' 100 120 250.7
12 60 '2020/12/12' 100 120 250.7
13 60 '2020/12/13' 106 128 345.3
14 60 '2020/12/14' 104 132 379.3
15 60 '2020/12/15' 98 123 275.0
16 60 '2020/12/16' 98 120 215.2
17 60 '2020/12/17' 100 120 300.0
19 60 '2020/12/19' 103 123 323.0
20 45 '2020/12/20' 97 125 243.0
21 60 '2020/12/21' 108 131 364.2
23 60 '2020/12/23' 130 101 300.0
24 45 '2020/12/24' 105 132 246.0
25 60 '2020/12/25' 102 126 334.5
26 60 20201226 100 120 250.0
27 60 '2020/12/27' 92 118 241.0
29 60 '2020/12/29' 100 132 280.0
30 60 '2020/12/30' 102 129 380.3
31 60 '2020/12/31' 92 115 243.0
"""
See the last result output doesn't have NaN values. inplace = True, it will clean in the same place.

dropna() will delete the rows with NaN.














































Pandas#01

 PANDAS [Basics]..

Pandas is a library used for working with data series | data matrix | datasets.

Pandas is useful for  analyzing using stat, cleaning messy data sets, exploring, and manipulating data.

"Pandas" is  "Python  Analysis for Data" and was created by Wes McKinney in 2008.

Pandas can find correlation between two columns or more. Aggregate functions like sum, average, min, max etc. can be easily found.

It is used in Python using import pandas 

It is used to create, manipulate and extract Data Frames.

import pandas as pd
biodata = {
'Name':['Raj', 'Ram','Sita', 'Laks'],
'Age' :[ 23, 23, 24, 21],
}


biof1 = pd.DataFrame(biodata)
print('bio 1=', biof1)


"""
bio 1= Name Age
0 Raj 23
1 Ram 23
2 Sita 24
3 Laks 21
"""


import pandas as pd
biodata = {
'Name':['Raj', 'Ram','Sita', 'Laks'],
'Age' :[ 23, 23, 24, 21],
}
biof1 = pd.DataFrame(biodata)
print('bio 1=', biof1)


"""
bio 1= Name Age
0 Raj 23
1 Ram 23
2 Sita 24
3 Laks 21
"""


biof1.to_csv('bio.csv')  #to save in a bio.csv file

It can be saved using biof1.to_csv('bio.csv')

biodata1 = {
'Name':['Raj', 'Ram','Sita', 'Laks'],
# 'Age' :[ 23, 23, 24, 21],
'Qual' :[ 'UG','PG', 'Phd','Phd'],
"Status" :['s','s','m','b']}

Note Dictionary is converted to data frame by pd.Dataframe()

If we have another data frame biof2, we can add both as below:


biof2 = pd.DataFrame(biodata1)
print(biof2)
"""
Name Qual Status
0 Raj UG s
1 Ram PG s
2 Sita Phd m
3 Laks Phd b
"""

result = pd.concat([biof1, biof2])
print(result)
"""
Name Age Qual Status
0 Raj 23.0 NaN NaN
1 Ram 23.0 NaN NaN
2 Sita 24.0 NaN NaN
3 Laks 21.0 NaN NaN
0 Raj NaN UG s
1 Ram NaN PG s
2 Sita NaN Phd m
3 Laks NaN Phd b
"""

biof1 and biof2 are combined. But notice the print out with NaN values. Then how to add with out this problem.

result1 = pd.concat([biof1, biof2], axis = 1)
print(result1)
"""
Name Age Name Qual Status
0 Raj 23 Raj UG s
1 Ram 23 Ram PG s
2 Sita 24 Sita Phd m
3 Laks 21 Laks Phd b
"""
# if dfs are same then use append()
result1 = pd.concat([biof1, biof2], axis=1)

SO easy.. axis =1 means by columns.

Now let us see how Series can be defined. How Data Frames can be accessedby row using df.loc() and columns by df["colname"]:

#refer to the row index:
print('\n',df.loc[0]) # First Row only
"""First Row
Name Annamalai
Age 90
Name: 0, dtype: object
"""
print('\n',df.loc[0:1]) # First, Second Row only
"""

Name Age
0 Annamalai 90
1 AMET 29
"""

print('\n',df["Age"]) # Accessing only Age Column values
"""
0 90
1 29
2 25
3 20
Name: Age, dtype: object
"""

To read csv file and load in df DataFrame

df = pd.read_csv('bio.csv')
print(df)
"""
Unnamed: 0 Name Age
0 0 Raj 23
1 1 Ram 23
2 2 Sita 24
3 3 Laks 21
"""

To read JSON file and print

import pandas as pd
df = pd.read_json('data.json')
print(df.head(5).to_string())
"""
Duration Pulse Maxpulse Calories
0 60 110 130 409.1
1 60 117 145 479.0
2 60 103 135 340.0
3 45 109 175 282.4
4 45 117 148 406.0
"""
print(df.tail(5).to_string())
"""
Duration Pulse Maxpulse Calories
164 60 105 140 290.8
165 60 110 145 300.4
166 60 115 145 310.2
167 75 120 150 320.4
168 75 125 150 330.4
"""

Please note JSON = Python Dictionary . JSON objects have the same format as Python dictionaries.

Reading by load() and writing a JSON File using dump():


import json
with open('data.json') as f:
data = json.load(f)

with open('data_new.json', 'w') as f:
json.dump(data, f, indent=2)
print("JSON file created from data.json file")


Monday 21 March 2022

Python#13 [Strings]

STRINGS

Prain Teaser 1:

import re
def clean_strings(strings):
result = []
print(len(strings))
for value in strings:
print(value)
value = value.strip()
value = re.sub('[!#?]', '', value)
value = value.title()
result.append(value)
return result

names = ['Rama ',' Laksmana',' Sita ']

print(clean_strings(names))

Result:

3
Rama
['Rama']

It is wrong out put. can you correct the code to get the out put as below. 

3
Rama
Laksmana
Sita
['Rama', 'Laksmana', 'Sita']


Other Useful Python String Operations 
#String

s1 = 'hello'
s2 = "Hello"
print(s1, s2) # hello Hello

docstr = """
This is multi line strings. Strings can be declared within \n Single quote \'
or Double Quote\" \n Note \ is used as escape character for quote.\n
String is an array of charecters just like in any other language.
"""
print(docstr)

hello = "Hello!"
for i in hello:
print(i) # To print character by character

# String functions


str = ' Mother, is superior, god '
print(len(str)) # 22
print('is' in str) # True
print('is' not in str) # False

print('was' in str) # False
print('was' not in str) # True

if 'was' not in str:
print('Was not present in Str')

# Slicing
print(str[:6]) # Mother : for from Beginning
print(str[0:6]) # Mother. Note 0 inclusive 6 exclusive
print(str[10:]) # T superior god : for up to end
print(str[-3:]) # God using negative indexing
print(str.upper()) # MOTHER IS SUPERIOR GOD
print(str.lower()) # mother is superior god
print(str.strip()) # Mother is superior god without spaces in the front and the end
print(str.replace("Mother", "Wife")) # Check Wife is superior God ...True!!!
print(str.split('.')) # [' Mother, is superior, god ']

s1 = 'Russia '
s2 = ' Ukraine'
s3 = 'x'
s4 = s1 + s3 + s2
print(s4) # Russia x Ukraine String Concatenation using +

# Formatting
lover = 'Juliat'
str = 'I am Romeo, i love\'o love {}'
print(str.format(lover)) # I am Romeo, i love'o love Juliat

times = 1000
str = 'I am Romeo, i love\'o love {} {} times' # many place holders {}
print(str.format(lover, times)) # I am Romeo, i love'o love Juliat 1000 times

str = 'I am Romeo, i love\'o love {1} times {0} ' # using Positional indexes
print(str.format(lover, times)) # I am Romeo, i love'o love 1000 times Juliat

str = "i love seetha ..mmm, \n also i love her sister <careless whisper>"
print(str) # using \n to new line : called as escape characters

print(str.title()) # I Love Seetha ..Mmm <CR> Also I Love Her Sister <Careless Whisper> Note capitals
print(str.split(',')) # ['i love seetha ..mmm', ' \nalso i love her sister <careless whisper>']
print("123".zfill(5)) #00123

str = 'sivaji vayile zilabee'
print(str[::-1]) # Reversal : # eebaliz eliyav ijavis

str1 = 'I am alive'
print(str1) # I am alive
del(str1)
#print(str1) # Name Error str1 is not defined

# String Alignment
str1 = "|{:<10}|{:^10}|{:>20}|".format('AMET', 'ODL', 'FOR E-Learning!')
# < for Left, ^ for Centre and > for Right
print("\nLeft, center and right alignment with Formatting: ")
print(str1) # print as below
"""#Left, center and right alignment with Formatting:
|AMET | ODL | FOR E-Learning!|"""
str2 = "\n{0:^12} was founded in {1:<4}!".format("AMET ODL FOR E-Learning!", 2022)
print('\n'+str1+'\n'+ str2)
"""
|AMET | ODL | FOR E-Learning!|

AMET ODL FOR E-Learning! was founded in 2022!
"""
In the above example various string operations are explained with the respective outputs as # comments

Happy Stringing in Python with AMET ODL ☝☝☝

Bonus :
{ for E-lite learners}
Jupyter Basics

You have to start with 

$ jupyter notebook

or

$ jupyter notebook --no--browser

Features ( Try these in Ipython)

  1. Tab Completion
  2. Introspection
  3. ? to display doc string
  4. %cmd anyScript.py where cmd = run. load etc.
  5. keyboard shortcuts like Unix bash shell
  6. Magic commands
    1. special commands not built in to python itself are known as magic commands
    2. Any command prefixed by %
    3. Eg. 
      1. aArray = np.random.randm(100,100)
      2. %timeit np.dot(aArray, aArray)
    4. %debug?
    5. %pwd
    6. %matplotlib inline
    7. eg: a ='apple'
      1. a <tab>
    8. duck typing

Python#12

Sets

Sets are used to store multiple items in a single variable

Sets are defined with {}.

Set is one of 4 built-in data types in Python used to store collections of data.

A set is a collection which is unorderedunchangeable*, and unindexed

Does not allow duplicate elements

set = {} will return data type as dictionary. SO we have to use set() method

to return <class: set>

Set Operations are explained in the following example code:



s1 = {}
print(type(s1))
#<class 'dict'>


s2 =set()
print(type(s2))
#<class 'set'>

s3 = set(("apple", "banana", "cherry")) # note the double round-brackets
print(s3) #{'banana', 'apple', 'cherry'}


aset ={1,2,3,4,5,5}
print(aset)
#{1, 2, 3, 4, 5}

aset =set("Hello")
print(aset)
#{'H', 'e', 'o', 'l'} -->order immaterial, only one l is printed


aset = set()
aset.add(11)
aset.add(22)
aset.add(33)


#aset.discard()
print(aset) #{33,11,22}
aset.pop()
print(aset) #{11,22}

#set Operations

odd = {1, 3, 5, 7, 9}
even = {0, 2, 4, 6, 8, 10}
primes = {3, 5, 7}

print(odd.union(even)) #{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}

print(odd.intersection(primes)) #{3, 5, 7}

print(even.intersection(primes)) #set()

print(odd.difference(primes)) #{1, 9}

print(odd.symmetric_difference(primes)) #{1, 9}

print(odd.symmetric_difference(even)) #{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}

a = {1,2,3,4,5,6,7,8,9}

b = {1,2,3,10,11,12}

a.update(b)

print(a) # {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}

a.intersection_update(b)

print(a) #{1, 2, 3, 10, 11, 12}

a.add(13)
print(a) # {1, 2, 3, 10, 11, 12, 13}

print(b) #{1, 2, 3, 10, 11, 12}

b.pop()

print(b) #{2, 3, 10, 11, 12}

def odd_even():
n = int(input('EnterNumper < 10 Please')) #5
if n in odd:
print('Odd number')
elif n in even:
print('Even number')

# odd_even() # Odd Number

print(a.issuperset(b)) # True

print(a.isdisjoint(b)) # False


c ={7,8,9}

print(a.isdisjoint(c)) # True

d = c # copy the reference be careful when u change the original alsowill change
print(c,d) #{8, 9, 7} {8, 9, 7}
d.add(18)
print(c,d) # {8, 9, 18, 7} {8, 9, 18, 7} dangerous original also changed


c ={7,8,9}
d = c.copy()
d.add(18)
print(c,d) # {8, 9, 7} {8, 9, 18, 7}

The results are given in the same line as comments for easy reference and understanding.

Happy set learning with AMETODL😈😈😈

Sunday 20 March 2022

Python#11 (Multi Processing)

 MULTI PROCESSING


How to make python do process simultaneously ?  Is it Possible? 

DO many things at a time? OMNI POTENT? 

Python supports multi processing. It utilizes the multi cores and Multi CPU's and speed up the process time.

Process:
  • Process is an instance of a program
  • Starting a process is slower that starting a thread
  • Larger memory footprint
  • IPC (inter-process communication) is more complicated

Thread

  • A thread is an light weight process  within a process that can be scheduled for execution               . 
  • A Process can spawn multiple threads.  
  • Key facts: - Multiple threads can be spawned within one process. Memory is shared between all threads 
  • Starting a thread is faster than starting a process - Great for I/O-bound tasks - Light weight - low memory footprint
  • One GIL( Global interpreter lock) for all threads, i.e. threads are limited by GIL 
  • Multithreading has no effect for CPU-bound tasks due to the GIL - Not interruptible/killable -> be careful with memory leaks - increased potential for race conditions

In this, we will take care  of Multiprocessing. Multithreading, we will take later. Open PyCharm IDE. Open project. Give any name as project name. In main.py. Type in /copy paste the following code and Run. It is Simple Processing to multiply.  

import time

start =time.perf_counter()

def multiplication_table(begin, end):

for i in range(begin, end+1):

for j in range(begin, end+1):
#temp = i * j

print(f'{i:<4}*{j:4} ={i * j:6}')

multiplication_table(1,5000)

finish =time.perf_counter()

print(f'\nSingle Finished in {round(finish-start, 2)}second(s)')

"""
Single Finished in 510.05second(s)
"""
Let us Multiprocessing the same print multiplication operation for  P1, 5000 using 5 Processes P1 with 1,1000, P2 with 1001,2000, P3 with 2001 to 3000, P4 with 3001 to 4000, P5 with 4001 to 5000.


import multiprocessing

import time


start=time.perf_counter()


def print_multi(begin, end):

for i in range(begin, end + 1):

for j in range(begin, end + 1):

temp = i * j

print(f'T{i:<4}*{j:4} ={i * j:6}')

if __name__ == "__main__":


p1 = multiprocessing.Process(target=print_multi, args=(1, 1000))
p2 = multiprocessing.Process(target=print_multi, args=(1001, 2000))
p3 = multiprocessing.Process(target=print_multi, args=(2001, 3000))
p4 = multiprocessing.Process(target=print_multi, args=(3001, 4000))
p5 = multiprocessing.Process(target=print_multi, args =(4001, 5000))

p1.start()
p2.start()
p3.start()
p4.start()
p5.start()

p1.join()
p2.join()
p3.join()
p4.join()
p5.join()
# print("Done")
finish = time.perf_counter()

print(f'MULTI in {round(finish-start, 2)} seconds (s)\n')

"""
MULTI in 80.44 seconds (s)
"""

See the difference  510.05  - 80.44 =     429.61 seconds

For Many Processes, You can save Time. You can spend this quality time with your family 🐤🐤🐤 

Happy Digital Learning with AMET!!!

Making Prompts for Profile Web Site

  Prompt: Can you create prompt to craft better draft in a given topic. Response: Sure! Could you please specify the topic for which you...