TIMINGS (added Feb 2018 per comments from devinbost claiming that this method is slow...)
First, lets create a dataframe with 30k columns:
n = 10000
cols = ['{0}_{1}'.format(letters, number)
for number in range(n) for letters in ('d', 't', 'didi')]
df = pd.DataFrame(np.random.randn(3, n * 3), columns=cols)
>>> df.shape
(3, 30000)
>>> %timeit df[[c for c in df if c[0] == 'd']] # Simple list comprehension.
# 10 loops, best of 3: 16.4 ms per loop
>>> %timeit df[[c for c in df if c.startswith('d')]] # More 'pythonic'?
# 10 loops, best of 3: 29.2 ms per loop
>>> %timeit df.select(lambda col: col.startswith('d'), axis=1) # Solution of gbrener.
# 10 loops, best of 3: 21.4 ms per loop
>>> %timeit df.filter(regex=("d.*")) # Accepted solution.
# 10 loops, best of 3: 40 ms per loop
On a larger dataset especially, a vectorized approach is actually MUCH FASTER (by more than two orders of magnitude) and is MUCH more readable.
I'm providing a screenshot as proof.
(Note: Except for the last few lines I wrote at the bottom to make my point clear with a vectorized approach, the other code was derived from the answer by @Alexander.)
Here's that code for reference:
import pandas as pd
import numpy as np
n = 10000
cols = ['{0}_{1}'.format(letters, number)
for number in range(n) for letters in ('d', 't', 'didi')]
df = pd.DataFrame(np.random.randn(30000, n * 3), columns=cols)
%timeit df[[c for c in df if c[0] == 'd']]
%timeit df[[c for c in df if c.startswith('d')]]
%timeit df.select(lambda col: col.startswith('d'), axis=1)
%timeit df.filter(regex=("d.*"))
%timeit df.filter(like='d')
%timeit df.filter(like='d', axis=1)
%timeit df.filter(regex=("d.*"), axis=1)
%timeit df.columns.map(lambda x: x.startswith("d"))
columnVals = df.columns.map(lambda x: x.startswith("d"))
%timeit df.filter(columnVals, axis=1)