10

I need to select columns in Pandas which contain only numeric values in column names, for example:

df=
          0     1     2     3     4 window_label next_states       ids
0      17.0  18.0  16.0  15.0  15.0        ddddd           d      13.0
1      18.0  16.0  15.0  15.0  16.0        ddddd           d      13.0
2      16.0  15.0  15.0  16.0  15.0        ddddd           d      13.0
3      15.0  15.0  16.0  15.0  17.0        ddddd           d      13.0
4      15.0  16.0  15.0  17.0   NaN        ddddd           d      13.0

so I need to select only first five columns. Something like:

df[df.columns.isnumeric()]

EDIT

I came up with the solution:

digit_column_names = [num for num in list(df.columns) if isinstance(num, (int,float))]
df_new = df[digit_column_names]

not very pythonic or pandasian, but it works.

Arnold Klein
  • 2,956
  • 10
  • 31
  • 60

5 Answers5

10

Try

df.ids = df.ids.astype('object')    
new_df = df.select_dtypes([np.number])


    0       1       2       3       4       
0   17.0    18.0    16.0    15.0    15.0    
1   18.0    16.0    15.0    15.0    16.0    
2   16.0    15.0    15.0    16.0    15.0    
3   15.0    15.0    16.0    15.0    17.0    
4   15.0    16.0    15.0    17.0    NaN     

EDIT: If you are interested in selecting column names that are numeric, here is something that you can do.

df = pd.DataFrame({0: [1,2], '1': [3,4], 'blah': [5,6], 2: [7,8]})
df.columns = pd.to_numeric(df.columns, errors = 'coerce')
df[df.columns.dropna()]

You get

    0.0 1.0 2.0
0   1   3   7
1   2   4   8
Vaishali
  • 37,545
  • 5
  • 58
  • 86
2

How about this solution?
This checks if every character of the column is a digit.

cols = [col for col in df.columns if all(char.isdigit() for char in col)]
df[cols]
igorkf
  • 3,159
  • 2
  • 22
  • 31
1

Here is an answer for the EDIT part:

i've intentionally created a mixture of column names as real numbers and strings that can be converted to numbers:

In [44]: df.columns.tolist()
Out[44]: [0, 1, 2, 3, '4', 'window_label', 'next_states', 'ids']
# NOTE:                ^

we can use pd.to_numeric(..., errors='coerce') method:

In [41]: df.columns[pd.to_numeric(df.columns, errors='coerce').to_series().notnull()]
Out[41]: Index([0, 1, 2, 3, '4'], dtype='object')

In [42]: cols = df.columns[pd.to_numeric(df.columns, errors='coerce').to_series().notnull()]

In [43]: df[cols]
Out[43]:
      0     1     2     3     4
0  17.0  18.0  16.0  15.0  15.0
1  18.0  16.0  15.0  15.0  16.0
2  16.0  15.0  15.0  16.0  15.0
3  15.0  15.0  16.0  15.0  17.0
4  15.0  16.0  15.0  17.0   NaN
MaxU - stand with Ukraine
  • 205,989
  • 36
  • 386
  • 419
1

I found another question on this website that is pretty related. I used the code from that and applied it to your problem. I also threw a float into the column names to make sure it worked with int and float. It looks like:

import pandas as pd

df = pd.DataFrame({0: [17.0, 18, 16, 15, 15],
                   1: [18.0, 16, 15, 15, 16],
                   2.0: [16.0, 15, 15, 16, 15],
                   3: [15.0, 15, 16, 15, 17],
                   4: [15.0, 16, 15, 17, None],
                   'window_label': ['ddddd' for i in range(5)],
                   'next_states': ['d' for i in range(5)],
                   'ids': [13.0 for i in range(5)]})

num_cols = []
for col in df.columns.values:
    try:
        float(col)
        num_cols.append(col)
    except ValueError:
        pass

print(df[num_cols])

and the result looks like:

      0     1   2.0     3     4
0  17.0  18.0  16.0  15.0  15.0
1  18.0  16.0  15.0  15.0  16.0
2  16.0  15.0  15.0  16.0  15.0
3  15.0  15.0  16.0  15.0  17.0
4  15.0  16.0  15.0  17.0   NaN

Edit1: I just realized that you can keep the numeric determiner in a generator function and have a slightly faster/certainly less memory intensive way of doing the same thing.

import pandas as pd


def is_num(cols):
    for col in cols:
        try:
            float(col)
            yield col
        except ValueError:
            continue

df = pd.DataFrame({0: [17.0, 18, 16, 15, 15],
                   1: [18.0, 16, 15, 15, 16],
                   2.0: [16.0, 15, 15, 16, 15],
                   3: [15.0, 15, 16, 15, 17],
                   4: [15.0, 16, 15, 17, None],
                   'window_label': ['ddddd' for i in range(5)],
                   'next_states': ['d' for i in range(5)],
                   'ids': [13.0 for i in range(5)]})

print(df[[col for col in is_num(df.columns.values)]])

yields the exact same result as above, although it is somewhat less readable.

Community
  • 1
  • 1
Eric Ed Lohmar
  • 1,832
  • 1
  • 17
  • 26
0

If you are only looking for numeric column names I think this should work:

df.columns[df.columns.str.isnumeric()]

or this

df.iloc[:,df.columns.str.isnumeric()]
Moondra
  • 4,399
  • 9
  • 46
  • 104
  • I am trying to get only numeric columns names . i applied your first code. and getting this error : ValueError: Cannot mask with non-boolean array containing NA / NaN values – Govinda Raju Nov 07 '20 at 05:25
  • The proper solution here would be `df.iloc[:, df.columns.map(str).str.isnumeric()]` – Peter Nov 17 '20 at 09:12