applying a method to a few selected columns in a pandas dataframe
Question:
I would like to apply a little method to several columns in a Dataframe. The method color_negative can’t be applied to columns with strings, therefore I need to skip these columns somehow. I could think of two approaches to solve the problem, though sadly none is working.
-
In approach 1:
I try to apply the method to every column one by one skipping the first one by using the index of the Dataframe and by setting the incrementing counter of the while loop to 1. When executing this approach I get the error, that the ‘Series’ object has no attribute ‘style’, so apparently, I can’t apply a method to a single column.
-
In approach 2:
I try to use the subset to apply the method only to those columns with numeric values, though I’m not sure if I use subset correctly. When executing this approach I get the error that the object of type ‘Styler’ has no len()
.
Here a simplified example:
import pandas as pd
d = {'col1': ['a', 'b'], 'col2': [21, 22], 'col3': [3, 51]}
df = pd.DataFrame(data=d)
def color_negative_red(val):
color = 'black'
if val < -1 : color = 'red'
if val > 1 : color = 'green'
return 'color: %s' % color
i=1
while i <= len(df):
#Approach 1
df.iloc[:, i] = df.iloc[:, i].style.applymap(color_negative_red)
#Approach 2
df = df.style.applymap(color_negative_red, subset = df.iloc[:, i])
i+=1
df
Has anyone a suggestion on how to solve this problem?
Answers:
you can select the wanted columns and then applymap
on them, as such:
column_names = ['name_a','name_b']
df[column_names] = df[column_names].applymap(my_func)
if you want you can filter out columns that are string
from numpy.core.multiarray import dtype
column_names = [name for name,col_type in df.dtypes.items() if col_type!=dtype('O')]
You can use style.Styler.apply
with DataFrame of styles
with numpy.select
for filling:
d = {'col1': ['a', 'b'], 'col2': [21, 22], 'col3': [0, -51]}
df = pd.DataFrame(data=d)
def color_negative_red(x):
#select only numeric columns
x1 = x.select_dtypes(np.number)
c1 = 'color: red'
c2 = 'color: green'
c3 = ''
#boolean masks
m1 = x1 < -1
m2 = x1 > 1
#numpy array by conditions
arr = np.select([m1, m2], [c1, c2], default=c3)
df1 = pd.DataFrame(arr, index=df.index, columns=x1.columns)
#added strings columns filled by c3 string
df1 = df1.reindex(columns=x.columns, fill_value=c3)
return df1
df.style.apply(color_negative_red, axis=None)
Vectorize your function
import numpy as np
f = np.vectorize(color_negative_red)
Then you can use simple apply
, while filtering by the column name as desired:
df.apply(lambda x: f(x) if x.name not in ['col1'] else x)
# col1 col2 col3
# 0 a color: green color: green
# 1 b color: green color: green
I would like to apply a little method to several columns in a Dataframe. The method color_negative can’t be applied to columns with strings, therefore I need to skip these columns somehow. I could think of two approaches to solve the problem, though sadly none is working.
-
In approach 1:
I try to apply the method to every column one by one skipping the first one by using the index of the Dataframe and by setting the incrementing counter of the while loop to 1. When executing this approach I get the error, that the ‘Series’ object has no attribute ‘style’, so apparently, I can’t apply a method to a single column.
-
In approach 2:
I try to use the subset to apply the method only to those columns with numeric values, though I’m not sure if I use subset correctly. When executing this approach I get the error that the object of type ‘Styler’ has no
len()
.
Here a simplified example:
import pandas as pd
d = {'col1': ['a', 'b'], 'col2': [21, 22], 'col3': [3, 51]}
df = pd.DataFrame(data=d)
def color_negative_red(val):
color = 'black'
if val < -1 : color = 'red'
if val > 1 : color = 'green'
return 'color: %s' % color
i=1
while i <= len(df):
#Approach 1
df.iloc[:, i] = df.iloc[:, i].style.applymap(color_negative_red)
#Approach 2
df = df.style.applymap(color_negative_red, subset = df.iloc[:, i])
i+=1
df
Has anyone a suggestion on how to solve this problem?
you can select the wanted columns and then applymap
on them, as such:
column_names = ['name_a','name_b']
df[column_names] = df[column_names].applymap(my_func)
if you want you can filter out columns that are string
from numpy.core.multiarray import dtype
column_names = [name for name,col_type in df.dtypes.items() if col_type!=dtype('O')]
You can use style.Styler.apply
with DataFrame of styles
with numpy.select
for filling:
d = {'col1': ['a', 'b'], 'col2': [21, 22], 'col3': [0, -51]}
df = pd.DataFrame(data=d)
def color_negative_red(x):
#select only numeric columns
x1 = x.select_dtypes(np.number)
c1 = 'color: red'
c2 = 'color: green'
c3 = ''
#boolean masks
m1 = x1 < -1
m2 = x1 > 1
#numpy array by conditions
arr = np.select([m1, m2], [c1, c2], default=c3)
df1 = pd.DataFrame(arr, index=df.index, columns=x1.columns)
#added strings columns filled by c3 string
df1 = df1.reindex(columns=x.columns, fill_value=c3)
return df1
df.style.apply(color_negative_red, axis=None)
Vectorize your function
import numpy as np
f = np.vectorize(color_negative_red)
Then you can use simple apply
, while filtering by the column name as desired:
df.apply(lambda x: f(x) if x.name not in ['col1'] else x)
# col1 col2 col3
# 0 a color: green color: green
# 1 b color: green color: green