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?
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 |
+----+-----------+-------------+
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.
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
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
Additional Sources:
Appending a list as dataframe row
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.
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?
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 |
+----+-----------+-------------+
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.
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
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)
anddf.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
Additional Sources:
Appending a list as dataframe row
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.