1

I am trying to add column according to the existing column in dataframe following this page.
Since there are many if case, I defined the if case as function (getDirection method) and tried to call by apply method(addDirection method).
Howerver, I got following error.

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

Can anyone tell how I can call function by apply for dataframe?
Code is shown below.

def addDirection(self):
    group=self.group
    group['direction']=group['Azimuth [deg]'].apply(self.getDirection)

   def getDirection(angle):
        if angle < 11.25 or angle >= 348.75:
            return "N"
        elif angle < 33.75 and angle >= 11.25:
            return "NNE"
        elif angle < 56.25 and angle >= 33.75:
            return "NE"
        elif angle < 78.75 and angle >= 56.25:
            return "ENE"
        elif angle < 101.25 and angle >= 78.75:
            return "E"
        elif angle < 123.75 and angle >= 101.25:
            return "ESE"
        elif angle < 146.25 and angle >= 123.75:
            return "SE"
        elif angle < 168.75 and angle >= 146.25:
            return "SSE"
        elif angle < 191.25 and angle >= 168.75:
            return "S"
        elif angle < 213.75 and angle >= 191.25:
            return "SSW"
        elif angle < 236.25 and angle >= 213.75:
            return "SW"
        elif angle < 258.75 and angle >= 236.25:
            return "WSW"
        elif angle < 281.25 and angle >= 258.75:
            return "W"
        elif angle < 303.75 and angle >= 281.25:
            return "WNW"
        elif angle < 326.25 and angle >= 303.75:
            return "NW"
        elif angle < 348.75 and angle >= 326.25:
            return "NNW"
Katsuya Obara
  • 903
  • 3
  • 14
  • 30
  • How did you `apply` the `getDirection()` method? – akilat90 Dec 03 '17 at 14:13
  • 1
    `getDirection` appears to be a method in some class, not a regular function. – chepner Dec 03 '17 at 14:20
  • @akilat90 Referring to this [page](https://stackoverflow.com/questions/36213383/pandas-dataframe-how-to-apply-function-to-a-specific-column), I suppose below script is applying the getDirection() method to dataframe. 'group['direction']=group['Azimuth [deg]'].apply(self.getDirection)' – Katsuya Obara Dec 03 '17 at 14:20
  • This is a lot more concisely implemented as a `list` lookup: `return ["N", "NNE", "NE, "ENE", ...][int((angle*100)//1125]`. – chepner Dec 03 '17 at 14:27
  • How are you calling addDirection? – Bharath M Shetty Dec 03 '17 at 14:51

2 Answers2

4

When calling self.getDirection(a), you are implicitly calling getDirection(self, a). This is why the error message states that two arguments were given instead of one (self and the element of the series).

The way you call the function (prepending self.) implies that it is not a static method, but rather an instance method. Instance methods are defined inside a class; their result typically depends on the internal state of the object (instance of the class) you are calling it on.

If you called the function as an instance method by mistake, you should write apply(getDirection) instead of apply(self.getDirection). Most likely this is what you want, since the function's outcome depends only on angle and not on any object's internal state.

If you want getDirection to be an instance method, define the function as def getDirection(self, a). You don't have to change anything else.

See also this answer on instance and class methods.

Cornflex
  • 639
  • 5
  • 15
2

As @Cornflex said is because you are passing additional paramter using self so you got that error. Either do def getDirection(self,angle) or just apply.(getDirection)

Since its pandas instead of that many if else's we can just do binning using pd.cut i.e

df = pd.DataFrame({'Azimuth [deg]':[300,340,150]})
bins = [11.25, 33.75, 56.25, 78.75, 101.25, 123.75, 146.25, 168.75, 191.25, 213.75, 236.25, 258.75, 281.75, 303.75, 326.25, 348.75]

labels = ['NNE', 'NE', 'ENE', 'E', 'ESE', 'SE', 'SSE', 'S', 'SSW', 'SW', 'WSW', 'W', 'WNW', 'NW', 'NNW']

pd.cut(df['Azimuth [deg]'],bins=bins,labels=labels).fillna('N') # fillna is for your first condition.

0    WNW
1    NNW
2    SSE
Name: Azimuth [deg], dtype: category
Categories (15, object): [NNE < NE < ENE < E ... W < WNW < NW < NNW]
In [557]:

df['Azimuth [deg]'].apply(getDirection)

0    WNW
1    NNW
2    SSE
Name: Azimuth [deg], dtype: object 
Bharath M Shetty
  • 30,075
  • 6
  • 57
  • 108