Saswat Padhi's solution is very cool, but it's not very efficient. If your problem was efficiency, you can consider my solution(with regex) to be around 2 times faster.
This is my code:
import re
columns = df.columns
skipped = '[ &()]'
formatted_columns = [re.sub(skipped, '', col).lower() for col in columns]
df.columns = formatted_columns
Here are the measurements:
1. regex
%%timeit
columns = df.columns
formatted_columns = [re.sub(skipped, '', col).lower() for col in columns]
df.columns = formatted_columns
# 231 µs ± 56.2 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
2. str.lower() and str.replace()
%%timeit
df.columns = df.columns.str.replace('[ &()]', '').str.lower()
# 483 µs ± 112 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
%%timeit
df.columns = df.columns.str.lower().str.replace('[ &()]', '')
# 500 µs ± 71.4 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
You can find a beautiful answer Replacing two characters, where you can find many comparisons on execution times.