Is it possible to put the Pandas dataframe column header as a footer instead?

Question:

I have a numpy array, and for simplicity sake it is empty.
The dimensions are 8×12 . I have my row and column headers defined.

column = [_ for _ in 'ABCDEFGH']
row = list(range(12, 0, -1))
self.board = np.full((12, 8, '||')
dataframe = pd.DataFrame(self.board, index=row, columns=column)

It looks like this:

     A   B   C   D   E   F   G   H
12  ||  ||  ||  ||  ||  ||  ||  ||
11  ||  ||  ||  ||  ||  ||  ||  ||
10  ||  ||  ||  ||  ||  ||  ||  ||
9   ||  ||  ||  ||  ||  ||  ||  ||
8   ||  ||  ||  ||  ||  ||  ||  ||
7   ||  ||  ||  ||  ||  ||  ||  ||
6   ||  ||  ||  ||  ||  ||  ||  ||
5   ||  ||  ||  ||  ||  ||  ||  ||
4   ||  ||  ||  ||  ||  ||  ||  ||
3   ||  ||  ||  ||  ||  ||  ||  ||
2   ||  ||  ||  ||  ||  ||  ||  ||
1   ||  ||  ||  ||  ||  ||  ||  ||

I want to know if I can put the column at the bottom instead of the top?

Asked By: shelbaz

||

Answers:

If you are interested in monospace output for your pandas data frame, you may want to check out tabulate.

While it does not support footers, it works nicely out of the box with pandas data frames.

from tabulate import tabulate
import pandas as pd

df = pd.DataFrame({'col_two' : [0.0001, 1e-005 , 1e-006, 1e-007],
                   'column_3' : ['ABCD', 'ABCD', 'long string', 'ABCD']})
print(tabulate(df, headers='keys', tablefmt='psql'))

+----+-----------+-------------+
|    |   col_two | column_3    |
|----+-----------+-------------|
|  0 |    0.0001 | ABCD        |
|  1 |    1e-05  | ABCD        |
|  2 |    1e-06  | long string |
|  3 |    1e-07  | ABCD        |
+----+-----------+-------------+
Answered By: noddy

I was looking for an answer to the same problem which is why I found your question.
I know this response is 25 days late but It’s my first response on StackOverflow (or any site for that matter) so I’m doing it anyway.
Also, maybe somebody else needs an answer to this in the future. I hope this helps.

I’m a newbie so I’m happy to receive pointers/criticism (no matter how big or small) on how I responded.

In order to recreate your df mockup, I had to fix some parentheses in your code and
get rid of ‘self’ as part of the variable b/c it generated an error for me.
Also, I added the sort_index() to reverse the index as you have it.

    import numpy as np
    import pandas as pd

    column = [_ for _ in 'ABCDEFGH']
    row = range(12, 0, -1)
    # board = np.full((12, 8), 7) # to test dtype changes
    board = np.full((12, 8), '||')
    df0 = pd.DataFrame(board, index=row, 
    columns=column).sort_index(ascending=False)

Manually create dict where keys = column.values and values = strings of the same names.

    footer = {'A':'A', 'B':'B', 'C':'C', 'D':'D', 'E':'E', 'F':'F', 'G':'G', 'H':'H'}

Or make python do it for you

    keys = list(df0.columns.values)
    values = list(df0.columns.values)
    footer = dict(zip(keys, values))

Append df0 with the dict.

    df1 = df0.append(footer, ignore_index=True)

Got footer but didn’t reverse index.
An error “Can only append a Series if ignore_index=True or if the Series has a name”, which is why the index isn’t reversed.
So this could work for others who don’t have that need to reverse the index.
It’s what I needed for displaying Headers and Footers for baseball stats.

    df2 = df0.append(pd.Series((pd.Series(footer)), name='Footer'))  # Change 'Footer' to any text

Had to put the footer into nested pd.Series() and add a name to remedy the above error.
Without the nesting you get this error: “append() got an unexpected keyword argument ‘name'”

    df3 = df0.append(pd.Series((pd.Series(footer)), name=''))  # Same as df2 but blank name

df0 matches your mockup dataframe.
df1 is the solution with untitled footer but ascending index.
df2 is the solution with titled footer and correct index.
df3 is the solution with untitled footer and correct index.

All of the above have both Headers and Footers, and OP wanted just footers. So, I found this below to finish the task:
Pandas – delete column name
@jezrael gave this succinct line to get rid of the headers (but with safety caveats – might be best to keep both headers and footers.)

    df4 = df3
    df4.columns = [''] * len(df4.columns)

    print(df4)  # OP's solution

Appending a series of strings to existing DF columns will convert all dtypes to objects.

I think the workaround here if you need to calc over columns, would be to calc over the columns of df0 instead of
those of df4, store them where you want, then get them into df4 to display df4 with the new data.

I hope that helps.

Answered By: Kurt Siepman

Well, this is a bit of a hack, but for display purposes it is a very quick way to get your column names at the foot of your output in a way that maintains the width:

dataframe = dataframe.append(pd.Series(name='col'))
dataframe.iloc[ len(dataframe) - 1 ] = dataframe.columns

Obviously, that last row will only be useful for display purposes:

      A   B   C   D   E   F   G   H
12   ||  ||  ||  ||  ||  ||  ||  ||
11   ||  ||  ||  ||  ||  ||  ||  ||
10   ||  ||  ||  ||  ||  ||  ||  ||
9    ||  ||  ||  ||  ||  ||  ||  ||
8    ||  ||  ||  ||  ||  ||  ||  ||
7    ||  ||  ||  ||  ||  ||  ||  ||
6    ||  ||  ||  ||  ||  ||  ||  ||
5    ||  ||  ||  ||  ||  ||  ||  ||
4    ||  ||  ||  ||  ||  ||  ||  ||
3    ||  ||  ||  ||  ||  ||  ||  ||
2    ||  ||  ||  ||  ||  ||  ||  ||
1    ||  ||  ||  ||  ||  ||  ||  ||
col   A   B   C   D   E   F   G   H
Answered By: zephyr707

I am amazed that this post isn’t more popular as I find it quite useful to have the column names at the bottom.

I am new to Pandas as well and used to SQL Insert and Update statements. It seems that inserting a new row into Pandas DataFrame is not as straightforward as you would think as there is no specific function to insert new rows in the DataFrame and it can be done in quite many ways.

Seems that the most popularly used method for inserting a new row into the DataFrame is to use .append() either in a DataFrame or dictionary format.

I found that you can insert rows into the DataFrame using at least four different methods: .append(), .concat(), .loc[] and .iloc[].

You can use any of these to insert the column names at the bottom of the DataFrame. Some of them have been already explained in this post. I have combined here different methods including @Kurt Siepman and @zephyr707 and added a couple more.

Step 1

Get column names from the existing DataFrame as an list.

columns_list = df.columns.values.tolist()

Convert the list of column names to the preferred datatype. DataFrame, dictionary or Pandas Series.

columns_df = pd.DataFrame([columns_list], columns=columns_list)
columns_dict = dict(zip(columns_list, columns_list))
columns_series = pd.Series(columns_list, index=columns_list)
columns_dict_manual = {"column_1":"column_1", "column_2":"column_2", "column3":"column_3"}

Step 2

Insert the column names to the DataFrame, either using .append(), .concat(), .loc[] or .iloc[].

.abbend() DataFrame, dictionary or series

df = df.append(columns_df, ignore_index=True) # append dataframe
df = df.append(columns_dict, ignore_index=True) # append dictionary
df = df.append(columns_series, ignore_index=True) # append series

.concat() DataFrame (Works only for DataFrame)

df = pd.concat([df, columns_df], ignore_index=True, axis=0)

.loc[] list or series

df.loc[len(df)] = columns_list # insert list row to the bottom
df.loc[len(df)] = columns_series # insert series row to the bottom

# Insert a row to the top
df.loc[-1] = columns_list # inserting a row
df.index = df.index + 1 # shifting index
df = df.sort_index() # sorting by index

.iloc[] list or series

df = df.append(pd.Series(), ignore_index=True) # Insert empty row
df.iloc[len(df) - 1] = columns_series # Insert columns to existing empty row

.loc[] and .iloc[] Notes!

  • Adding a row at a specific index position will replace the existing row at that position.
  • When using .iloc[] to add a row, the DataFrame must already have a row in the position
  • len(df) and df.shape[0] returns the length of the DataFrame.
  • len(df) is apparently faster.

Extra Step

You might find it useful to also add the sum of columns at the bottom

Note! This needs to be done before inserting the columns at the bottom.

df = df.append(df.sum(numeric_only=True), ignore_index=True)

Main Sources:

Pandas Add Row to DataFrame – Definitive Guide

Pandas Cheat Sheet

Additional Sources:

Appending a list as dataframe row

Get a list from Pandas DataFrame column headers

Insert a row to pandas dataframe

Answered By: Tim

If you just need to print it with a header on the bottom, try:

df = pd.DataFrame({'a': [1,2], 'b':[3,4]})

df_string = df.to_string()
header = df_string.split('n')[0]

print(f'{df_string}n{header}')

Printing:

   a  b
0  1  3
1  2  4
   a  b

This will probably break for MultiIndex.

Answered By: Voy