score calculator with python and pandas - python

I'm trying to make a simple app to get the score of anyone on a test from the following formula:
score=(grade-average)/variance
for example if your score out of 20 is 18 and the average of the class is 15 then this formula helps you to understand how is your grade in comparison to others.
my code opens an excel file located in my pc in reads the points column writes them to a list then gets the average and variance and uses the formula.
this is my excel file.
BTW the grades in the excel are just for testing.
I've tried these to codes(I'm not that pro in using classes and I was trying to make some use of it):
this is the first one
class taraz:
def __init__(self,file_name,file_dir,your_point):
self.file_name=file_name
self.file_dir=file_dir
self.your_point=your_point
def sum_ave():
f=pandas.read_excel(r (file_dir))
point_list=f['point'].tolist()
sum1=sum(point_list)
ave1=sum1/len(point_list)
def variance():
for i in point_list:
var1=sqrt(((i-ave1)**2)/len(point_list))
def taraz1():
taraz1=(your_point-ave1)/var1
print(taraz1)
print(taraz1)
this is the second one:
def taraz(file_name,file_dir,your_point):
def sum_ave():
f=pandas.read_excel(r (file_dir))
point_list=f['point'].tolist()
sum1=sum(point_list)
ave1=sum1/len(point_list)
def variance():
for i in point_list:
var1=sqrt(((i-ave1)**2)/len(point_list))
def taraz1():
taraz1=(your_point-ave1)/var1
print(taraz1)
from the first code I just got and output like this:
<main.taraz object at 0x02528130>
and from the second one I don't get an output at all.
will be glad to use your tips thanks anywas.

Firstly, understand the scope of variable. If a variable is declared inside a method it will be accessible from that method only unless it is declared as global.
When it comes to your code, variance method inside your class.
def variance():
for i in point_list:
var1=sqrt(((i-ave1)**2)/len(point_list))
How the variance method will understand point_lits variable. It is neither defined not declared as global/class variable.
Second, Methods of a class will take a default parameter usually defined as self unless it is decorated as a classmethod. check here to understand about self keyword.
Third, Classes will be having objects but functions won't. So you are not able to see the bound object with the function.
So, code after adding self keyword will look like this
from os import path
class Taraz:
def __init__(self, file_name, file_dir, your_point):
self.file_name = file_name
self.file_dir = file_dir
self.your_point = your_point
self.point_list = None
self.ave1 = None
def sum_ave(self):
f = pandas.read_excel(path.join(self.file_dir, self.file_name))
self.point_list = f['point'].tolist()
sum1 = sum(self.point_list)
self.ave1 = sum1 / len(self.point_list)
def variance(self):
if self.point_list is not None and self.ave1 is not None:
for i in self.point_list:
var1 = sqrt(((i-self.ave1)**2) / len(self.point_list))
def taraz1(self):
taraz1 = (self.your_point - self.ave1) / var1
print(taraz1)
Edit:
>>> def func():
... pass
...
>>> class cla:
... pass
...
>>> func()
>>>
>>> cla()
<__main__.cla object at 0x0000019A55944550>
>>> func
<function func at 0x0000019A552D2EA0>
>>> cla
<class '__main__.cla'>
() are used to call the method or function. Here func is a function and cla is a class. When you call a class it will return the object of the class so you see <main.cla object at 0x0000019A55944550>, but when you call function it will return the response of the function. Since my function is not having anything here, it retuned nothing.

There is no reason to use pandas to read from the excel file and then convert it into a list and re-implement basic vector operations such as mean and variance.
from os import path
import pandas as pd
class Taraz:
def __init__(self, filepath):
scores = pd.read_excel(filepath)['point']
self.mean = scores.mean()
self.var = scores.var()
def score(self, score):
return (score - self.mean) / self.var
if __name__ == '__main__':
taraz = Taraz(path.join('path', 'to', 'the', 'file.xlsx'))
print(taraz.score(16))
Output:
-0.012571428571428395
In your examples you have several errors that I would like to comment.
Variable scope is important. If you assign a variable inside a function, it will be assigned just inside that function. Outside of it will raise a NameError.
Methods first argument (which should be called self except for some special methods) is the instance itself, where we can assign values that will be stored in the instance and later retrieve them. For example, in the constructor (__init__) method of the code above, we are assigning somehting to self.mean and that value will be stored in the instance so that we can later use it in out score method.
OOP (Object Oriented Programming) is a very well stablished coding pattern, but trying to force the use of a class for something that doesn't really represent a type seems a bit unnecesary. This could be achieved in a single function easily:
from os import path
import pandas as pd
def taraz(filepath):
scores = pd.read_excel(filepath)
mean = scores['point'].mean()
var = scores['point'].var()
scores['scores'] = (scores['point'] - mean) / var
return scores
if __name__ == '__main__':
print(taraz(path.join('path', 'to', 'the', 'file.xlsx')))
Output:
name point scores
0 tghi 15 -0.163429
1 nghi 16 -0.012571
2 asghr 15 -0.163429
3 sbhn 20 0.590857
4 tghi 12 -0.616000
5 nghi 20 0.590857
6 asghr 17 0.138286
7 sbhn 18 0.289143
8 tghi 17 0.138286
9 nghi 16 -0.012571
10 asghr 15 -0.163429
11 12 -0.616000
As you can see, pandas dataframes implement vector operations, so (scores['point'] - mean) / var is translated to a vector of integers minus a float, divided by a float, and ther result of that operation is a vector of floats, that we store in the column 'scores'. This way we compute the scores for every row.

Related

Why do function attributes (setattr ones) only become available after assigning it as a property to a class and instantiating it?

I apologize if I'm butchering the terminology. I'm trying to understand the code in this example on how to chain a custom function onto a PySpark dataframe. I'd really want to understand exactly what it's doing, and if it is not awful practice before I implement anything.
From the way I'm understanding the code, it:
defines a function g with sub-functions inside of it, that returns a copy of itself
assigns the sub-functions to g as attributes
assigns g as a property of the DataFrame class
I don't think at any step in the process do any of them become a method (when I do getattr, it always says "function")
When I run a (as best as I can do) simplified version of the code (below), it seems like only when I assign the function as a property to a class, and then instantiate at least one copy of the class, do the attributes on the function become available (even outside of the class). I want to understand what and why that is happening.
An answer [here(https://stackoverflow.com/a/17007966/19871699) indicates that this is a behavior, but doesn't really explain what/why it is. I've read this too but I'm having trouble seeing the connection to the code above.
I read here about the setattr part of the code. He doesn't mention exactly the use case above. this post has some use cases where people do it, but I'm not understanding how it directly applies to the above, unless I've missed something.
The confusing part is when the inner attributes become available.
class SampleClass():
def __init__(self):
pass
def my_custom_attribute(self):
def inner_function_one():
pass
setattr(my_custom_attribute,"inner_function",inner_function_one)
return my_custom_attribute
[x for x in dir(my_custom_attribute) if x[0] != "_"]
returns []
then when I do:
SampleClass.custom_attribute = property(my_custom_attribute)
[x for x in dir(my_custom_attribute) if x[0] != "_"]
it returns []
but when I do:
class_instance = SampleClass()
class_instance.custom_attribute
[x for x in dir(my_custom_attribute) if x[0] != "_"]
it returns ['inner_function']
In the code above though, if I do SampleClass.custom_attribute = my_custom_attribute instead of =property(...) the [x for x... code still returns [].
edit: I'm not intending to access the function itself outside of the class. I just don't understand the behavior, and don't like implementing something I don't understand.
So, setattr is not relevant here. This would all work exactly the same without it, say, by just doing my_custom_attribute.inner_function = inner_function_one etc. What is relevant is that the approach in the link you showed (which your example doesn't exactly make clear what the purpose is) relies on using a property, which is a descriptor. But the function won't get called unless you access the attribute corresponding to the property on an instance. This comes down to how property works. For any property, given a class Foo:
Foo.attribute_name = property(some_function)
Then some_function won't get called until you do Foo().attribute_name. That is the whole point of property.
But this whole solution is very confusingly engineered. It relies on the above behavior, and it sets attributes on the function object.
Note, if all you want to do is add some method to your DataFrame class, you don't need any of this. Consider the following example (using pandas for simplicity):
>>> import pandas as pd
>>> def foobar(self):
... print("in foobar with instance", self)
...
>>> pd.DataFrame.baz = foobar
>>> df = pd.DataFrame(dict(x=[1,2,3], y=['a','b','c']))
>>> df
x y
0 1 a
1 2 b
2 3 c
>>> df.baz()
in foobar with instance x y
0 1 a
1 2 b
2 3 c
That's it. You don't need all that rigamarole. Of course, if you wanted to add a nested accessor, df.custom.whatever, you would need something a bit more complicated. You could use the approach in the OP, but I would prefer something more explicit:
import pandas as pd
class AccessorDelegator:
def __init__(self, accessor_type):
self.accessor_type = accessor_type
def __get__(self, instance, cls=None):
return self.accessor_type(instance)
class CustomMethods:
def __init__(self, instance):
self.instance = instance
def foo(self):
# do something with self.instance as if this were your `self` on the dataframe being augmented
print(self.instance.value_counts())
pd.DataFrame.custom = AccessorDelegator(CustomMethods)
df = pd.DataFrame(dict(a=[1,2,3], b=['a','b','c']))
df.foo()
The above will print:
a b
1 a 1
2 b 1
3 c 1
Because when you call a function the attributes within that function aren't returned only the returned value is passed back.
In other words the additional attributes are only available on the returned function and not with 'g' itself.
Try moving setattr() outside of the function.

How to access the namespace of a function in python

How do I access the namespace of another module or function in python?
For example, let's say I have access to a function f that has been passed, and I want get a variable it has access to.
class function_creator():
def __init__(self, start_num):
self.number = start_num
def getfunc(self):
def nestedfunc():
print(f'The number you were trying to find was {self.number}')
self.number += 1
return nestedfunc
f = function_creator(5).getfunc()
Running f() will print the number, however I cannot find how to access it directly.
The way you're calling the code, there's not a good way to get at that number. But if you saved the instance of function_creator to a variable, you'd be able to get at it more easily:
fc = function_creator(5)
f = fc.getfunc()
f()
print(fc.number)
While I said there isn't an good way to access the value, it is possible by diving into the internals of the function object, as the function is a closure on the self variable from getfunc. You can get the value of that self argument from f using f.__closure__[0].cell_contents, and then get the number by checking its number attribute:
f = function_creator(5).getfunc()
f()
fc = f.__closure__[0].cell_contents
print(fc.number)
This is CPython specific, and probably won't work in other Python interpreters.

Python: How do I fix my code so that the append will add the argument to the list?

I am very new to python and I've been trying to do this code where i use a tkinter button command to run a function, it works but the append() is not executing, meaning it does not append to the list.
The list and the function containing the append is outside the class and is then classed within a class through the use of tkinter button command
I've tried putting the function inside the class, it works but the append is not adding into the list again.
This is the code I've made that is somewhat similar to real one
prices = []
f = True
class firstclass():
def __init__(self):
while f == True:
my_function()
f = False
def my_function():
prices.append(70)
class secondclass():
def __init__(self):
pass
print(sum(prices))
the sample of real code is in this link, please take this into consideration as well
python: Appending a value to a list outside the class, function with append also outside the class, but function is called within a class
I expected that it would print the appended value which is 70, but it still printed 0
A few issues you need to deal with. First assigning f=True outside the class won't change the value inside, so if you instantiated the class it would just throw an UnboundLocalError complaining that f isn't initialized. You can try this yourself by instantiating the class with
fc = firstclass()
Without instantiation, you have no hope of it giving you the value you want. It is printing zero because of the function secondclass, which has a print statement that is not contained within a method, so it prints the value sum(prices) which the class is declared. That value is from the original declared value of prices which is []. At least that is the way you have shown it in your question. I'm not sure whether you meant to indent the print statement, which would mean it is part of secondclass. However, if you didn't indent you would get the same result as you haven't instantiated firstclass.
To correct this, see below. This code will output 70 as you intended.
prices = []
class firstclass():
def __init__(self):
my_function()
def my_function():
prices.append(70)
class secondclass():
def __init__(self):
pass
print('before instantiation', sum(prices))
fc = firstclass()
print('after instantiation', sum(prices))
fc is now an object of type firstclass and the __init__ method has called my_function to append the value 70 to prices.
There are two reasons this is happening.
You never called firstclass to actually initialize the
constructor.
You are trying to assign False to the variable f
which does not belong to the scope of the class. If you still assign
it, it's considered local. And at the moment the interpreter
detects that you assigned it, the while loop does not have any local
reference of f since you did not define it under the constructor.
See this answer for more details.
Here is the completed code:
prices = []
class firstclass():
f = True
def __init__(self):
while self.f:
my_function()
self.f = False
def my_function():
prices.append(70)
class secondclass():
def __init__(self):
pass
firstclass()
print(sum(prices))

Using a function within a function

So I have a class with some functions. I want to use a function in another function to calculate the fuelconsumption.
I have the attribute self.consumption, which is calculated within the function Calculate_consumption.
Now I want to write a new function, which is updating the kilometer counter and also calculating if you are driving efficient.
So, I want to calculate the consumption by using the function Claculate_consumption and then see if it is bigger then 8 or not.
Well I tried to just write the function as I have found it here on Stackoverflow: How do you call a function in a function?
But this solution somehow does not work. Maybe somebody can point out my mistake.
class Car:
def __init__(self, kmDigit):
self.kmDigit = int(kmDigit)
self.Max = 8
self.consumption = 0
def Claculate_consumption(self, Liter, km):
self.consumption += (Liter/km)*100
return round(self.consumption, 2)
def Refuel(self,Liter, km):
self.kmDigit += km
print self.kmDigit
a = Claculate_consumption(Liter, km)
if a > self.Max:
b = self.consumption - self.Max
print 'Your fuel consumption is too high!'
else:
print 'Nice!'
I am getting a **NameError** in line 14, because Calculate_consumption is somehow a global name.
You have to write: a = self.Claculate_consumption(Liter, km)
because your program does not know where to look for this method. Self says that this method is in the same class in which you call the method
self : self represents the instance of the class. By using the "self" keyword we can access the attributes and methods of the class in python.
https://micropyramid.com/blog/understand-self-and-init-method-in-python-class/

How to import global variables in python from a class module in another file?

I have a file that contains the class definitions and functions I need to use in my main file to make the text cleaner. However, I'm having a problem with imported global variables.
There is plenty of information at SO and other resources regarding how to make function variables global within the same code or how to use the global variables from an imported file. However, there is no information on how to access a variable from an imported file if the variable belongs to a function belonging to a class.
I would appreciate any help on how to do it or why it cannot be done. Please skip the lecture on the dangers of using global variables like this as my situation requires such use.
Edit: Sorry for not having an example in the original post. It's my first one. Below is an example of what I'm trying to accomplish.
Let's say I have a file classes.py that contains:
class HelixTools():
def calc_angle(v1, v2):
v1_mag = np.linalg.norm(v1)
v2_mag = np.linalg.norm(v2)
global v1_v2_dot
v1_v2_dot = np.dot(v1,v2)
return v1_v2_dot
Then in my main text file I do:
from classes import HelixTools
ht = HelixTools()
v1 = some vector
v2 = some other vector
ht.calc_angle(v1,v2)
print(v1_v2_dot)
The result is "v1_v2_dot" not defined. I need v1_v2_dot to use it as the input of another function.
Here's an example of how you can access class attributes (if I understand what it is you want to do correctly). Lets imagine you have a python file called "Test_class.py" that contains the following code:
class Foo(object):
def __init__(self, x, y):
self.x = x
self.y = y
def bar(self):
self.z = self.x + self.y
Now lets imagine you want to import this class into another python file in the same directory, and access attributes of that class. You would do this:
from Test_class import Foo
# Initialize two Foo objects
test1 = Foo(5, 6)
test2 = Foo(2, 3)
# Access the x and y attributes from the first Foo object
print(test1.x) # This will print 5
print(test1.y) # This will print 6
# Access the x and y attributes from the second Foo object
print(test2.x) # This will print 2
print(test2.y) # This will print 3
# Access the z attribute from the first Foo object
test1.bar()
print(test1.z) # This will print 11
# Access the z attribute from the second Foo object
test2.bar()
print(test2.z) # This will print 5
This works because variables defined in the __init__ magic method are initialized as soon as the Foo object is first called, so the attributes defined here can be access immediately after. The bar() method has to be called before you can access the z attribute. I made 2 Foo objects just to show the importance of including "self." in front of your variables, in that each attribute is specific to that particular class instance.
I hope that answers your question, but it would be very helpful if you provided some example code to show exactly what it is you want to do.
You should likely use a class attribute to store this value. Note that the implementation will depend on what your class HelixTools really does.
But for the example, you could use something like this:
import numpy as np
class HelixTools():
def __init__(self):
# Initialize the attribute so you'll never get an error calling it
self.v1_v2_dot = None
def calc_angle(self, v1, v2): # Pass self as first argument to this method
v1_mag = np.linalg.norm(v1)
v2_mag = np.linalg.norm(v2)
# Store the value in the attribute
self.v1_v2_dot = np.dot(v1,v2)
And then:
from classes import HelixTools
ht = HelixTools()
v1 = some vector
v2 = some other vector
ht.calc_angle(v1,v2) # This will not return anything
print(ht.v1_v2_dot) # Access the calculated value

Categories