Feedback on first Class - Printable Version +- Python Forum (https://python-forum.io) +-- Forum: General (https://python-forum.io/forum-1.html) +--- Forum: Code sharing (https://python-forum.io/forum-5.html) +--- Thread: Feedback on first Class (/thread-11272.html) |
Feedback on first Class - fffrost - Jul-01-2018 Hi, I decided it was time to start learning to use classes. The goal was to write a class for a t-test that has various methods and class variables that I can call, for example my_ttest.t (which returns the 't' statistic). My issue is that, now I have finished it, I have never seen a class that contains this many self.? variables. Maybe I misunderstood something, but I do want to be able to say my_ttest.t, my_ttest.p, my_ttest.whatever. Maybe it would just be better if I didn't have this as a class? But that would only reinforce my thought that maybe I'll never need to make use of classes... I'm just looking for feedback on how to approach building classes like this. Here's the code (if you want to run then you'll need statsmodels, numpy, pandas, and scipy): class ttest_ind: """Takes two input vectors & carries out an independent-samples t-test for differences. Parametric hypothesis test for differences between two independent samples. self.x = x vector self.y = y vector self.dof_? = degree of freedom self.t_? = test statistic (t) self.p_? = significance p value self.r = Descriptive statistics and tests, see statsmodels.stats.api self.result_? = result tuple from ttest (t, p, dof) self.CI_? = confidence intervals self.cohen_d_? = cohen's d""" def __init__(self, x, y): self.x = x self.y = y # levene's test for homogeneity of variance self.levenes = stats.levene(self.x, self.y, center='mean') self.levenes_F = self.levenes[0] self.levenes_p = self.levenes[1] self.r = sms.CompareMeans(sms.DescrStatsW(self.x), sms.DescrStatsW(self.y)) self.result_equal = self.r.ttest_ind(usevar='pooled') self.t_equal, self.p_equal, self.dof_equal = self.result_equal[0], self.result_equal[1], self.result_equal[2] self.CI_equal = self.r.tconfint_diff(usevar='pooled') self.cohen_d_equal = np.mean(self.x) - np.mean(self.y) / self.r.std_meandiff_pooledvar self.result_uneq = self.r.ttest_ind(usevar='unequal') self.t_uneq, self.p_uneq, self.dof_uneq = self.result_uneq[0], self.result_uneq[1], self.result_uneq[2] self.CI_uneq = self.r.tconfint_diff(usevar='unequal') self.cohen_d_uneq = (np.mean(self.x) - np.mean(self.y)) / (np.sqrt((np.std(self.x, ddof=1) ** 2 + np.std(self.y, ddof=1) ** 2) / 2)) def summary(self): result_values = [self.levenes_F, self.levenes_p, self.t_equal, self.t_uneq, self.dof_equal, self.dof_uneq, self.p_equal, self.p_uneq, np.mean(self.x - self.y), stats.sem(self.x - self.y, ddof=1), self.CI_equal[0], self.CI_equal[1], self.CI_uneq[0], self.CI_uneq[1], self.cohen_d_equal, self.cohen_d_uneq] result_labels = ['Levene\'s F', 'Levene\'s p', 't (equal var.)', 't (unequal var.)', 'df (equal var.)', 'df (unequal var.)', 'Sig. (p, equal var.)', 'Sig. (p, unequal var.)', 'Mean difference', 'Std Error difference', '95% CI (lower) equal var.', '95% CI (upper) equal var.', '95% CI (lower) unequal var.', '95% CI (upper) unequal var.', 'Cohen\'s d (equal)', 'Cohen\'s d (unequal)'] return pd.Series(data=result_values, index=result_labels) RE: Feedback on first Class - ichabod801 - Jul-01-2018 That many attributes (self. variables) is not out of hand. I am frequently working with classes that have 26 attributes. Classes and functions are two different ways to organize your code. Both are ways to not write the same code over and over again. Should it be a class or a function? I don't know. Good reasons for classes: it's a big chunk of data you will access a lot or pass from function to function, it represents an object to you conceptually, it has a lot of related functions to turn into methods, you want to make collections of complicated results like lists or trees, you want to use it natively for things like print, len, sorting, equality testing, or math. Personally, it seems odd to make a t-test into an object to me. But that's me, and that's me not knowing what you want to do with this in your code. I can see situations where this would be useful, although I would add support for multiple comparisons in those situations. If you are going to go with this as a class, I would make result_labels a class attribute, rather than generating it each time you run summary. RE: Feedback on first Class - fffrost - Jul-01-2018 Ok! Thanks for the feedback. |