我正在寻找一种在python中将标量映射到十六进制颜色的快速方法:
import matplotlib
import matplotlib.cm as cm
import matplotlib.colors as mcol
np.random.seed(0)
df = pd.DataFrame(np.random.rand(20000,1))
df.head()
0
0 0.548814
1 0.715189
2 0.602763
3 0.544883
4 0.423655
我只有20种颜色,所以我想知道matplotlib是否是最好的解决方案,或者简单的查找表会更好。
colors = ["#084594", "#0F529E", "#1760A8", "#1F6EB3", "#2979B9", "#3484BE", "#3E8EC4",
"#4A97C9", "#57A0CE", "#64A9D3", "#73B2D7", "#83BBDB", "#93C4DE", "#A2CBE2",
"#AED1E6", "#BBD6EB", "#C9DCEF", "#DBE8F4", "#EDF3F9", "#FFFFFF"]
values = df[0].values
@profile
def apply_method(): # 6.9 sec
cm1 = mcol.ListedColormap(colors)
norm = matplotlib.colors.Normalize(vmin=np.min(values), vmax=np.max(values), clip=True)
mapper = cm.ScalarMappable(norm=norm, cmap=cm1)
return df[0].apply(lambda row: mcol.to_hex(mapper.to_rgba(row)))
%time apply_method()
从分析器我看到to_rgba()
是最昂贵的方法(6.5秒只有20.000个值)。
所以我正在寻找一种绕过to_rgba()方法的方法。有没有办法从cm.ScalarMappable获取颜色范围?然后查找正确的十六进制颜色?
答案 0 :(得分:2)
问题代码中最昂贵的方法不是to_rgba()
,而是DataFrame.apply
,因为它会将函数分别应用于每一行。
在我对这个问题的回答中给出了使用matplotlib色图的不同方法之间的比较:How do I map df column values to hex color in one go?
使用查找表(LUT)确实要快得多(在那里调查的情况下是因子400)。
但是请注意,在这个问题的情况下,根本不需要使用matplotlib。由于您已经有十六进制格式的可能颜色列表,因此绝对不需要使用matplotlib并将十六进制颜色转换为色彩映射,然后再转换为十六进制颜色。
而是直接使用颜色列表作为查找表(LUT)方式更快。使用具有10000个条目的数据帧(以使其与其他答案的时间保持一致),来自该问题的代码需要2.7秒。
以下代码需要380μs。这是7000倍的改进因素 与链接问题7.7 ms的答案中使用matplotlib的最佳方法相比,它仍然是20倍的优势。
import numpy as np; np.random.seed(0)
import pandas as pd
def create_df(n=10000):
return pd.DataFrame(np.random.rand(n,1), columns=['some_value'])
def apply(df):
colors = ["#084594", "#0F529E", "#1760A8", "#1F6EB3", "#2979B9", "#3484BE", "#3E8EC4",
"#4A97C9", "#57A0CE", "#64A9D3", "#73B2D7", "#83BBDB", "#93C4DE", "#A2CBE2",
"#AED1E6", "#BBD6EB", "#C9DCEF", "#DBE8F4", "#EDF3F9", "#FFFFFF"]
colors = np.array(colors)
v = df['some_value'].values
v = ((v-v.min())/(v.max()-v.min())*(len(colors)-1)).astype(np.int16)
return pd.Series(colors[v])
df = create_df()
%timeit apply(df)
# 376 µs