0

i am having a problem while working with apply method. so, i am trying to make the first and last letter of a series uppercase. First i have made a simple series i.e

s1 = pd.Series(['pandas','python','javascript','c#'])
s1

The output:

0        pandas
1        python
2    javascript
3            c#
dtype: object

When I make a simple function and run it. It works fine with no issue and gives me the output that I was hoping for.

def upp(x):
for i in x:
    print(f'{i[0].upper()}{i[1:-1].lower()}{i[-1].upper()}')

upp(s1)

Output:

PandaS
PythoN
JavascripT
C#

However, the output is not a series type, as I would want it to do further analysis. I ran a type method to check the type.

type(upp(s1))

Output:

NoneType

So, i guessed i have to use the apply method to get a series datatype. But, when i run apply method with the function. the result was not what i was hoping for.

def upp(x):
for i in x:
    print(f'{i[0].upper()}{i[1:-1].lower()}{i[-1].upper()}')
s1.apply(upp)

Output:

PP
HH
PP
PP
YY
TT
HH
OO
NN
JJ
AA
VV
AA
CC
##
0    None
1    None
2    None
3    None
dtype: object

Can anyone explain to me what is happening and where i am doing wrong and give more information on how to use and not use apply method? I am a beginner and practicing some questions. It will be a great help to understand this concept.

  • 1
    your function is just printing the result of `'{i[0].upper()}{i[1:-1].lower()}{i[-1].upper()}'`, and doesn't return anything. That's why the type of your output is `NoneType`. You should be using `return` additionally or instead of `print(...)` – Luise Sep 06 '20 at 16:35
  • related: [Python Function Returning None](https://stackoverflow.com/questions/21471876/python-function-returning-none) – anky Sep 06 '20 at 16:38
  • 1
    When using `.apply` on a `Series`, the function used is receiving one element of the series at a time, so the `for` loop in `upp` now iterates over individual characters of each value in the series, not over the series' elements themselves. – DeepSpace Sep 06 '20 at 16:41
  • FYI: When someone answers your question, please "accept it" if the answer is helpful. (click on the check mark beside the answer to toggle it from greyed out to filled in) [What should I do when someone answers my question?](https://stackoverflow.com/help/someone-answers) – hoomant Sep 07 '20 at 12:41
  • i didnt know, we can do that – Samrat Thapa Sep 08 '20 at 09:48

2 Answers2

3

Your function prints the result instead of returning it using return. Furthermore, the for loop is extra in your function as the .apply method applies the function to one item at a time.

You can change your function to:

def upp(x):
    return f'{x[0].upper()}{x[1:-1].lower()}{x[-1].upper()}'

s1.apply(upp)

Or, you can simply use a lambda function:

s1.apply(lambda x: f'{x[0].upper()}{x[1:-1].lower()}{x[-1].upper()}')
hoomant
  • 455
  • 2
  • 12
  • thanks.. i finally got it. i thought to pass all the values of a series we need to use a loop and then only we can pass them all. Nobody told or i think i missed it, when we pass a series to a function, it works on every element. – Samrat Thapa Sep 07 '20 at 04:29
  • @Samrat Thapa: BTW, looping using the `.apply` method is much faster compared to crude looping over the DataFrame using a `for` loop. (search "vectorization" for more information) – hoomant Sep 07 '20 at 12:36
2

You are almost there. The below answer could help:

import pandas as pd


s1 = pd.Series(['pandas','python','javascript','c#'])


def upp(x):
    return f'{x[0].upper()}{x[1:-1].lower()}{x[-1].upper()}'

s1 = s1.apply(upp)

print(s1)

Output:

0        PandaS
1        PythoN
2    JavascripT
3            C#
dtype: object

You don't need to use loop in upp().

CK__
  • 1,252
  • 1
  • 11
  • 25