To clarify what is actually causing your error: you can use any function within apply, but str.replace('z', '') is not a valid statement. This will throw an error on its own.
replace is a bound method for string objects. It is meant to be called on a string object, not on the string type:
'xyz'.replace('z', '')    # Returns 'xy'
str.replace('z', '')      # Throws TypeError (not enough arguments)
Neither of the above statements return a function, so the result cannot be used with apply. As in the answer by @jezrael, to use replace with apply, you need a function which takes one argument, such as a lambda.
The reason str.upper works, despite also being a bound method, is that it does not take any other arguments, and therefore can be called with one argument. So str.upper('xyz') is equivalent to the proper usage 'xyz'.upper(). You would see the same error as with your use of replace if you tried x['b'].apply(str.upper())