Convert column values to lower case only if they are string

What is the type of these columns to begin with? object? If so, you should just convert them:

df['my_col'] = df.my_col.astype(str).str.lower()

MVCE:

In [1120]: df
Out[1120]: 
   Col1
0   VIM
1   Foo
2  test
3     1
4     2
5     3
6   4.5
7   OSX

In [1121]: df.astype(str).Col1.str.lower()
Out[1121]: 
0     vim
1     foo
2    test
3       1
4       2
5       3
6     4.5
7     osx
Name: Col1, dtype: object

In [1118]: df.astype(str).Col1.str.lower().dtype
Out[1118]: dtype('O')

If you want to do arithmetic on these rows, you probably shouldn't be mixing strs and numeric types.

However, if that is indeed your case, you may typecast to numeric using pd.to_numeric(..., errors='coerce'):

In [1123]: pd.to_numeric(df.Col1, errors='coerce')
Out[1123]: 
0    NaN
1    NaN
2    NaN
3    1.0
4    2.0
5    3.0
6    4.5
7    NaN
Name: Col1, dtype: float64

You can work with the NaNs, but notice the dtype now.


The test in your lambda function isn't quite right, you weren't far from the truth though:

df.apply(lambda x: x.str.lower() if(x.dtype == 'object') else x)

With the data frame and output:

>>> df = pd.DataFrame(
    [
        {'OS': 'Microsoft Windows', 'Count': 3},
        {'OS': 'Mac OS X', 'Count': 4},
        {'OS': 'Linux', 'Count': 234},
        {'OS': 'Dont have a preference', 'Count': 0},
        {'OS': 'I prefer Windows and Unix', 'Count': 3},
        {'OS': 'Unix', 'Count': 2},
        {'OS': 'VMS', 'Count': 1},
        {'OS': 'DOS or ZX Spectrum', 'Count': 2},
    ]
)
>>> df = df.apply(lambda x: x.str.lower() if x.dtype=='object' else x)
>>> print(df)
                          OS  Count
0          microsoft windows      3
1                   mac os x      4
2                      linux    234
3     dont have a preference      0
4  i prefer windows and unix      3
5                       unix      2
6                        vms      1
7         dos or zx spectrum      2