-3

Im to trying run a Python script in Spyder IDE (Python 3.6) and as I progress Im starting to refactor it to more of OOP (Object Oriented) and hopefully a mature package.

I have a class titled (Epoch), see below:

class Epoch:

    def __init__(self):
        self.Epoch_Counter = 0 
        self.Timings = [] 
        self.Timings_millisec_ticks = [] 
        self.Duration_milli_secs = 0 
        self.Raw = []
        self.Stimulia = []
        self.Majority_stimulia = "NA"
        self.epoch = datetime.datetime.utcfromtimestamp(0)
        #median, positive area, negative area, geometric,max,ratio positive vs negative
        self._median = 0 
        self._mean = 0 
        self._positive_area = 0
        self._negative_area = 0 
        self._geometric_area = 0 
        self._max = 0 
        self._min = 0 
        self._max_amplitude = 0
        self._integral = 0 
        self._variance= 0 
        self._positive_to_negative_ratio = 0 
        self._skew = 0 
        self._kurtosis = 0 
        self.Components = [] 


    #mean
    def mean(self,value):
        self._mean = value

    def mean(self):
        return self._mean

    #median
    def median(self,value):
        self._median = value

    def median(self):
        return self._median

    #positive_area 
    def positive_area(self,value):
        self._positive_area = value


    def positive_area(self):
        return self._positive_area

    #negative_area
    def negative_area(self,value):
        self._negative_area = value


    def negative_area(self):
        return self._negative_area

    #geometric_area
    def geometric_area(self,value):
        self._geometric_area = value

    def geometric_area(self):
        return self._geometric_area

    def integral(self,value):
        self.integral = value

    def integral(self):
        return self.integral

    def max_amplitude(self,value):
        self._max_amplitude = value

    def max_amplitude(self):
        return self._max_amplitude

    def max_(self,value):
        self._max = value

    def max_(self):
        return self._max

    #min 
    def min_(self,value):
        self.min = value

    def min_(self):
        return self._min

    def positive_to_negative_ratio(self,value):
        self.positive_to_negative_ratio = value

    def positive_to_negative_ratio(self,value):
        return self._positive_to_negative_ratio

    #Timings_millisec_ticks
    def timings_millisec_ticks(self):
        return self.Timings_millisec_ticks

    def timings_millisec_ticks_append(self,value):
        self.Timings_millisec_ticks.append(value)

    #start_time
    def timings(self):
        return self.Timings

    def timings_append(self,value):
        self.Timings.append(value)

    #end_time
    def end_time(self):
        return self.Timings[len(self.Timings)-1]

    #start_time
    def start_time(self):
        return self.Timings[0]

    #duration 
    def duration_milli_secs(self):
        return self.Duration_milli_secs

    def duration_milli_secs(self):
        return self.unix_time_millis(self.str_to_datetime_(self.end_time())) - self.unix_time_millis(self.str_to_datetime_(self.start_time()))

    #raw
    def raw(self):
        return self.Raw

    def raw_append(self,value):
        self.Raw.append(value)

    #components
    def components(self):
        return self.Components

    def components_append(self,value):
        self.Components.append(value)

    #stimulia
    def stimulia_append(self,value):
        self.Stimulia.append(value)

    def stimulia(self):
        return self.Stimulia

    #variance 
    def variance(self):
        return self.variance

    def variance(self,value):
        self.variance = value

    #skew
    def skew(self,value):
        self._skew = value

    def skew(self):
        return self._skew

    def unix_time_millis(self,dt):
        return (dt - self.epoch).total_seconds() * 1000.0

    """ covert datetime of this format 2017-10-13 19:22:50:525 to datetime object"""
    def  str_to_datetime_(self,datetime_str):
     return datetime.datetime.strptime(datetime_str, '%Y-%m-%d %H:%M:%S:%f')

    def _print(self):
        return str(self.Epoch_Counter)+","+str(len(self.Timings))+","+str(self.duration_milli_secs())+","+str(len(self.Raw))+","+str(len(self.Stimulia))+","+str(self.majority_stimulia)

I have script that has function, that calculates summary statistics and attempts to set the value of the statistics in the Epoch object (mean,median,etc...), see below:

def get_epoch_summary_stats(eeg_record_epochs_):
    import numpy as np
    import scipy.stats as stats
    import pylab as pl
    ##stimulia
    stimulia_raw_median = []
    stimulia_raw_mean = [] 
    stimulia_raw_positive_area = [] 
    stimulia_raw_negative_area = []
    stimulia_raw_geometric_area = []
    stimulia_raw_max = [] 
    stimulia_raw_min = [] 
    stimulia_raw_positive_to_negative = []
    stimulia_variance = []
    stimulia_max_amplitude = [] 
    stimulia_integral = []
    stimulia_raw_kurtosis = [] 
    stimulia_raw_skew = []

    ##no stimulia
    no_stimulia_raw_median = []
    no_stimulia_raw_mean = []
    no_stimulia_raw_positive_area = [] 
    no_stimulia_raw_negative_area = []
    no_stimulia_raw_geometric_area = []
    no_stimulia_raw_max = [] 
    no_stimulia_raw_min = [] 
    no_stimulia_raw_positive_to_negative = []
    no_stimulia_variance = [] 
    no_stimulia_max_amplitude = [] 
    no_stimulia_integral = []
    no_stimulia_raw_kurtosis = [] 
    no_stimulia_raw_skew = []

    no_stimulia_class_count = 0 
    stimulia_class_count = 0


    epoch_durations = [] 

    stimulia_raws = []  
    no_stimulia_raws = [] 

    for item in eeg_record_epochs: 
        epoch_durations.append(item.duration_milli_secs())


    epoch_durations_sorted = sorted(epoch_durations)
    mean_duration = np.mean(epoch_durations_sorted)
    std_duration = np.std(epoch_durations_sorted)


    print("Input data:",path)


    print("Epoch duration(millisecs) - mean_duration:",mean_duration)
    print("Epoch duration(millisecs) - std_duration:",std_duration)
    #remove epoch that are more than 1 standard deviation away from the mean in epoch size 
    counter = 0
    for item in eeg_record_epochs_: 
        ##DURATION SELECTION RULE 
        if (item.duration_milli_secs() > (mean_duration + std_duration) or item.duration_milli_secs() < (mean_duration - std_duration)):
            del eeg_record_epochs[counter]
            ##print("epoch duration_milli_secs - REMOVED:",item.duration_milli_secs())
        else:

            ##print("epoch duration_milli_secs:",item.duration_milli_secs())
            #median, positive area, negative area, geometric area, max , ratio positive vs negative, ratio negative vs positive 
            raw_float_array = np.array(item.raw()).astype(np.float)
            #median
            item.median(np.median(raw_float_array))
            #mean 
            item.mean(np.mean(raw_float_array))
            ##print("raw median: ",item.median)
            positive_area = 0
            negative_area = 0
            #positive area
            for value in raw_float_array:
                if value > 0:
                    positive_area = positive_area + value

            item.positive_area(positive_area)
            ##print("raw positive_area:", item.positive_area)
            #negative area
            for value in raw_float_array:
                if value < 0 :
                    negative_area = negative_area + abs(value)

            item.negative_area(negative_area)
            ##print("raw negative_area:", item.negative_area)
            #geometric area 
            abs_raw_float_array = np.abs(raw_float_array)
            item.geometric_area(sum(abs_raw_float_array))
            ##print("raw geometric_area:", item.geometric_area)

            #max_
            item.max(max(raw_float_array))
            ##print("raw max_:",item.max_)
            #min
            item.min(min(raw_float_array))

            item.max_amplitude(max(max(raw_float_array),abs(min(raw_float_array))))

            item.integral(item.positive_area - abs(item.negative_area))
            ##print("raw min_:",item.min_)
            #min
            #positive_to_negative_ratio
            try:
                item.positive_to_negative_ratio=abs(item.positive_area/item.negative_area)
            except ZeroDivision as err:
                continue

            #variance 
            item.variance(np.var(raw_float_array))

            #skew
            item.skew(stats.skew(raw_float_array))

            #kurtosis
            item.kurtosis(stats.kurtosis(raw_float_array))

            ##print("raw positive_to_negative:",item.positive_to_negative_ratio)
            item.majority_stimulia()
            ##default NO_STIMULIA
            stimulia_class = "NO_STIMULIA"


            if  item.majority_stimulia().upper() == "ON":
                stimulia_class = "ON"
                print(stimulia_class)
                item.plot()


                for raw_value in item.raw():
                    stimulia_raws.append(int(raw_value))

                stimulia_raw_median.append(item.median) 
                stimulia_raw_mean.append(item.mean)
                stimulia_raw_positive_area.append(item.positive_area)
                stimulia_raw_negative_area.append(item.negative_area)
                stimulia_raw_geometric_area.append(item.geometric_area)
                stimulia_raw_max.append(item.max_)
                stimulia_raw_min.append(item.min_)
                stimulia_raw_mean.append(item.mean)
                stimulia_raw_skew.append(item.skew)
                stimulia_raw_kurtosis.append(item.kurtosis)
                stimulia_max_amplitude.append(item.max_amplitude)
                stimulia_integral.append(item.integral)
                ##append only if the number is not inf or nan but just a number 
                if is_not_inf_or_is_nan(item.positive_to_negative_ratio) != 1:
                    stimulia_raw_positive_to_negative.append(item.positive_to_negative_ratio)
                    ##print("item.positive_to_negative_ratio:",item.positive_to_negative_ratio)
                stimulia_variance.append(item.variance)
                stimulia_class_count=  stimulia_class_count + 1
                #P3 component stats +/- estimated peek for P3



            else:
                no_stimulia_class_count = no_stimulia_class_count + 1
                print(stimulia_class)
                item.plot()
                for raw_value in item.raw():
                    no_stimulia_raws.append(int(raw_value))

                no_stimulia_raw_median.append(item.median) 
                no_stimulia_raw_mean.append(item.mean)
                no_stimulia_raw_positive_area.append(item.positive_area)
                no_stimulia_raw_negative_area.append(item.negative_area)
                no_stimulia_raw_geometric_area.append(item.geometric_area)
                no_stimulia_raw_max.append(item.max_)
                no_stimulia_raw_min.append(item.min_)
                no_stimulia_raw_mean.append(item.mean)
                no_stimulia_raw_skew.append(item.skew)
                no_stimulia_raw_kurtosis.append(item.kurtosis)
                no_stimulia_max_amplitude.append(item.max_amplitude)
                no_stimulia_integral.append(item.integral)
                ##append only if the number is not inf or nan but just a number
                if is_not_inf_or_is_nan(item.positive_to_negative_ratio) != 1:
                    no_stimulia_raw_positive_to_negative.append(item.positive_to_negative_ratio)
                    ##print("item.positive_to_negative_ratio:",item.positive_to_negative_ratio)
                no_stimulia_variance.append(item.variance)

            ##print("majority stimulia:",item.Majority_stimulia)


            counter = counter + 1
            ##component_extraction(item,"ON",300,200,800)

    print("ON summary stats-")

    mean_plot = float(sum(stimulia_raw_mean)/counter)
    std_plot = float(math.sqrt(sum(stimulia_variance)/counter))
    fit = stats.norm.pdf(sorted(stimulia_raws), mean_plot, std_plot)  #this is a fitting indeed
    pl.plot(sorted(stimulia_raws),fit,'-o')
    pl.hist(sorted(stimulia_raws),normed=True)      #use this to draw histogram of your data
    pl.show() 



    print("stimulia_class_count:",stimulia_class_count)
    print("average stimulia_raw_mean:",sum(stimulia_raw_mean)/counter)
    print("average stimulia_raw_median:",sum(stimulia_raw_median)/counter)
    print("average stimulia_raw_positive_area:",sum(stimulia_raw_positive_area)/counter)
    print("average stimulia_raw_negative_area:",sum(stimulia_raw_negative_area)/counter)
    print("average stimulia_raw_geometric_are:",sum(stimulia_raw_geometric_area)/counter)
    print("average stimulia_raw_max:",sum(stimulia_raw_max)/counter)
    print("average stimulia_raw_min:",sum(stimulia_raw_min)/counter)
    print("average stimulia_max_amplitude:",sum(stimulia_max_amplitude)/counter)
    print("average stimulia_integral:",sum(stimulia_integral)/counter)
    print("average stimulia_variance:",sum(stimulia_variance)/counter)
    print("average stimulia_std:",math.sqrt(sum(stimulia_variance)/counter))
    print("average stimulia_skew:",sum(stimulia_raw_skew)/counter)
    print("average stimulia_kurtosis:",sum(stimulia_raw_kurtosis)/counter)
    print("average stimulia_raw_positive_to_negative:",sum(stimulia_raw_positive_to_negative)/counter)

    print("NO_STIMULIA summary stats-")

    mean_plot = float(sum(no_stimulia_raw_mean)/counter)
    std_plot = float(math.sqrt(sum(no_stimulia_variance)/counter))
    fit = stats.norm.pdf(sorted(no_stimulia_raws), mean_plot, std_plot)  #this is a fitting indeed
    pl.plot(sorted(no_stimulia_raws),fit,'-o')
    pl.hist(sorted(no_stimulia_raws),normed=True)      #use this to draw histogram of your data
    pl.show()

    print("no_stimulia_class_count:",no_stimulia_class_count)
    print("average no_stimulia_raw_mean:",sum(no_stimulia_raw_mean)/counter)
    print("average no_stimulia_raw_median:",sum(no_stimulia_raw_median)/counter)
    print("average no_stimulia_raw_positive_area:",sum(no_stimulia_raw_positive_area)/counter)
    print("average no_stimulia_raw_negative_area:",sum(no_stimulia_raw_negative_area)/counter)
    print("average no_stimulia_raw_geometric_are:",sum(no_stimulia_raw_geometric_area)/counter)
    print("average no_stimulia__raw_max:",sum(no_stimulia_raw_max)/counter)
    print("average no_stimulia_raw_min:",sum(no_stimulia_raw_min)/counter)
    print("average no_stimulia_max_amplitude:",sum(no_stimulia_max_amplitude)/counter)
    print("average no_stimulia_integral:",sum(no_stimulia_integral)/counter)
    print("average no_stimulia_variance:",sum(no_stimulia_variance)/counter)
    print("average no_stimulia_std:",math.sqrt(sum(no_stimulia_variance)/counter))
    print("average no_stimulia_skew:",sum(no_stimulia_raw_skew)/counter)
    print("average no_stimulia_kurtosis:",sum(no_stimulia_raw_kurtosis)/counter)
    print("average no_stimulia_raw_positive_to_negative:",sum(no_stimulia_raw_positive_to_negative)/counter)

When running the script, I get an error:

File "", line 1, in get_epoch_summary_stats(eeg_record_epochs)

File "", line 425, in get_epoch_summary_stats item.median(np.median(raw_float_array))

TypeError: median() takes 1 positional argument but 2 were given

How can I fix the Epoch class or my call to item.median() in order to set Epoch's median attribute without getting this error.

Thanks a million!

cyber101
  • 2,822
  • 14
  • 50
  • 93

3 Answers3

3

There is no method overloading in python. If you define median function twice, the second definition will be used. Therefore in your code, the second definition is used, i.e.,

def median(self):
    return self._median

So it only takes one positional argument (self).

It seems what you want to define is a getter and a setter. In python, you can do it by adding functional decorators. For example:

@property
def median(self):
    return self._median

@median.setter
def median(self, value):
    self._median = value

The first one is a getter for median, and the second one is a setter. When you invoke print(self.median), the first function will be called, while if you execute self.median = 5, the second function will be called.

You can read this article for more information about getter and setters in python: http://stackabuse.com/python-properties/

Maokai
  • 364
  • 1
  • 5
  • This is not how the OP is currently using `self.median`, but this is the correct way to do what the OP wants to do. – TemporalWolf Jan 15 '18 at 21:41
  • That's right. THanks for the clarification. – Maokai Jan 15 '18 at 21:44
  • 2
    @TemporalWolf I would say the *correct* way is *not to use properties until you need to actually control access*. As it stands, the Pythonic way is simply to omit all of these methods – juanpa.arrivillaga Jan 15 '18 at 21:50
  • @TemporalWolf, I updated my Epoch class , now when I run the code I get: item.median(np.median(raw_float_array)) TypeError: 'int' object is not callable , I read on stackoverflow that since median is being set to 0 in constructor "median=0" then median is being treated as a int rather than function. – cyber101 Jan 19 '18 at 02:10
  • @AryanNaim Because it's an attribute, not a function: `item.median = np.median(raw_float_array))` – TemporalWolf Jan 19 '18 at 18:41
1

You are defining median two times:

#median
def median(self,value):
    self._median = value

def median(self):
    return self._median

The second definition is used, which does not accept a second argument named value.

Christian Dean
  • 22,138
  • 7
  • 54
  • 87
Gianluca
  • 3,227
  • 2
  • 34
  • 35
0

Adding to the other answer as he was correct. Try to focus on changing your functions to getters and setters. Should help out in the long run.

Clannadqs
  • 307
  • 3
  • 12