Remember Python is 0-indexed, so the 2nd element is 1. The last element of an iterable is -1, so the second-to-last is -2. So, modify your return statement to say
return serie.map(lambda x: x[0] + x[1].upper() + x[2:-2] + x[-2].upper() + x[-1])
It's a little bulky, but I think it works for your input:
>>> x = ["python", "php", "java", "javascript", "c++", "sql"]
>>> serie = pd.Series(x)
>>> serie.map(lambda x: x[0] + x[1].upper() + x[2:-2] + x[-2].upper() + x[-1])
0 pYthOn
1 pHHp
2 jAVa
3 jAvascriPt
4 c+++
5 sQQl
Wait, it returned pHHp, c+++, and sQQl for "php", "c++", and "sql", respectively. If I try a 2-character string, like "c#", I get "c#C#". And if I try giving it just a single letter, like "c", it dies with an IndexError.
You need to check the length of the string before you pass it to the lambda, which would be completely unreadable if you tried to put it all in a single lambda. Instead, define a function and use that.
def two_caps(thing: str) -> str:
if len(thing) > 3:
new_thing = thing[0] + thing[1].upper() + thing[2:-2] + thing[-2].upper() + thing[-1]
elif len(thing) == 3:
new_thing = thing[0] + thing[1].upper() + thing[2]
else:
new_thing = thing
return new_thing
This returns properly-capitalized strings for inputs >= 3. If the len() is < 3, it returns the original thing. Now you can use this return statement:
return serie.Map(lambda x: two_caps(x))
and you should be good to go.