时间日期
dt对象
常用属性
- date、time、year、month、day、hour、minute、second、quarter
- dayofweek、dayofyear
- daysinmonth:返回对应月的天数
- month_name()、day_name():返回月份和周几的英文名
- is_month_end、is_month_start、is_year_start、is_year_end、is_leap_year(判断是否是闰年)
操作
- round、ceil、floor
- strftime:对时间格式化
- isocalendar().week:返回时间序列的周数
1 2 3 4 5 6 7 8 9 10 11
| s = pd.Series(pd.date_range('2021-1-1 20:35:00', '2021-1-1 22:35:00', freq='45min'))
s.dt.ceil(freq="1h") ''' 0 2021-01-01 21:00:00 1 2021-01-01 22:00:00 2 2021-01-01 23:00:00 dtype: datetime64[ns] '''
|
date_range
1
| pd.date_range("20210101", "20210201", freq="WOM-1MON")
|
pd.period_range
1 2 3 4 5 6 7 8
| p_month = pd.Period("2024-01",freq="M") print("Period对象:", p_month) print("该时间段的开始时间:", p_month.start_time) print("该时间段的结束时间:", p_month.end_time)
pd.period_range(start='2023Q1', end='2024Q4', freq='Q')
|
pd.Timestamp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| import datetime pd.Timestamp(datetime.datetime(2026,1,1,12,0,0))
pd.Timestamp("2025-01-01T12:30:00")
pd.Timestamp(2026,1,1,12,0,0)
pd.Timestamp(1513393355.5, unit="s")
pd.Timestamp("now") pd.Timestamp('today').date() pd.Timestamp("now").replace(year=2025,day=1)
ts = pd.Timestamp("now")
"ts 的时刻是{y}年{m}月{d}日{h}点{min}分{s}秒".format( y=ts.year, m=ts.month, d=ts.day, h=ts.hour, min=ts.minute, s=ts.second )
ts.value
ts.strftime("%Y-%m-%d")
|
pd.to_datetime
1 2 3 4 5
| pd.to_datetime("20000101", format=r"%Y%m%d", errors="ignore")
pd.to_datetime(1490195805, unit="s")
|
时间日期格式化符号
- %y 两位数的年份表示(00-99)
- %Y 四位数的年份表示(000-9999)
- %m 月份(01-12)
- %d 月内中的一天(0-31)
- %H 24小时制小时数(0-23)
- %I 12小时制小时数(01-12)
- %M 分钟数(00-59)
- %S 秒(00-59)
pd.date_range
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| pd.date_range('2021-9-1','2021-9-21', freq='10D') ''' DatetimeIndex( ['2021-09-01', '2021-09-11', '2021-09-21'], dtype='datetime64[ns]', freq='10D') '''
pd.date_range('2021-9-1', '2021-10-28', periods=6) ''' DatetimeIndex(['2021-09-01 00:00:00', '2021-09-12 09:36:00', '2021-09-23 19:12:00', '2021-10-05 04:48:00', '2021-10-16 14:24:00', '2021-10-28 00:00:00'], dtype='datetime64[ns]', freq=None) '''
|
索引访问
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| rng = pd.date_range('1/1/2021', '12/1/2021', freq='BM') ts = pd.Series(np.random.randn(len(rng)), index=rng)
ts['2021'] ts['2021-6'] ts['2021-6':'2021-10'] dft['2013-1':'2013-2-28 00:00:00'] dft['2013-1-15':'2013-1-15 12:30:00'] dft2.loc['2013-01-05']
idx = pd.IndexSlice dft2.loc[idx[:, '2013-01-05'], :]
df['2019-01-01 12:00:00+04:00':'2019-01-01 13:00:00+04:00']
|
截断索引
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| rng2 = pd.date_range('2011-01-01', '2012-01-01', freq='W') ts2 = pd.Series(np.random.randn(len(rng2)), index=rng2)
ts2.truncate(before='2011-11', after='2011-12') ''' 2011-11-06 0.437823 2011-11-13 -0.293083 2011-11-20 -0.059881 2011-11-27 1.252450 Freq: W-SUN, dtype: float64 '''
ts2['2011-11':'2011-12'] ''' 2011-11-06 0.437823 2011-11-13 -0.293083 2011-11-20 -0.059881 2011-11-27 1.252450 2011-12-04 0.046611 2011-12-11 0.059478 2011-12-18 -0.286539 2011-12-25 0.841669 Freq: W-SUN, dtype: float64 '''
|
rolling滑窗
1 2 3 4 5 6 7
| np.random.seed(999) s = pd.Series(np.random.randint(0, 10, 365), index=pd.date_range("20210101","20211231")) s = s.sample(250, random_state=999).sort_index()
s.rolling("7D").sum().head(8)
|
shift移动
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| rng = pd.date_range("2026-01-01", "2026-01-03") ts = pd.Series(range(len(rng)), index=rng)
ts.shift(3, freq=pd.offsets.BDay()) """ 2026-01-06 0 2026-01-07 1 2026-01-07 2 dtype: int64 """
ts.shift(3, freq="BME") """ 2026-03-31 0 2026-03-31 1 2026-03-31 2 dtype: int64 """
|
as_freq频率转换
方法内部会自动构造出一个索引作为结果序列的索引。该索引通过pd.date_range()构造:
以原序列的第一个值为起始值(start),以原序列的最后一个值为终止值(end),以给定的freq 为采样频率
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| s = pd.Series( [1, 2, np.nan, 4], index=pd.to_datetime(["20210901", "20210908", "20210910", "20210915"]), )
s.asfreq("3D", method="ffill") ''' 2021-09-01 1.0 2021-09-04 1.0 2021-09-07 1.0 2021-09-10 NaN 2021-09-13 NaN Freq: 3D, dtype: float64 '''
s.asfreq("3D", method="bfill") ''' 2021-09-01 1.0 2021-09-04 2.0 2021-09-07 2.0 2021-09-10 NaN 2021-09-13 4.0 Freq: 3D, dtype: float64 '''
|
Timedelta
Timedelta:参数weeks、days、hours、minutes、seconds、milliseconds、microseconds 和nanoseconds
1 2 3 4 5 6 7 8 9 10 11 12 13
| pd.Timedelta("1d2h")
pd.Timedelta(days=1,hours=2)
pd.to_timedelta([1,2,3],unit="d")
pd.timedelta_range("0s","1000s",freq="6min") pd.timedelta_range("0s","1000s",periods=3)
|
Timedelta序列的dt 对象上定义的属性只有days、seconds、microseconds和nanoseconds
seconds:seconds 不是本身的秒数,而是对天数取余后剩余的秒数。具体地说,假设时间差为1 分6 秒,seconds 属性返回的是66
秒而不是6 秒
total_seconds()获取总共的秒数,对其进行60取余,可获得对应秒的数据
DateOffset
日期偏置类型及其含义
| 偏置类型(B 表示工作日) |
含义 |
BDay |
工作日 |
CDay |
自定义日 |
Week |
星期或周 |
WeekOfMonth |
每月第x 周的第y 天 |
LastWeekOfMonth |
每月最后一周的第y 天 |
(B)MonthBegin/(B)MonthEnd |
月初/月末 |
(B)QuarterBegin/(B)QuarterEnd |
季初/季末 |
(B)YearBegin/(B)YearEnd |
年初/年末 |
DateOffset 类似于时间差 Timedelta ,但它使用日历中时间日期的规则,而不是直接进行时间性质的算术计算,让时间更符合实际生活
DateOffset中例如year和years参数,year设置年份优先运行,years偏移再运行,再按时间粒度从大到小(比如先运算years再运算months)叠加偏移量
- 场景 1:跨月末的 “1 个月” 偏移(核心差异)
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| import pandas as pd from datetime import datetime, timedelta
dt = datetime(2024, 1, 31)
offset_1m = pd.DateOffset(months=1) dt_offset = dt + offset_1m print(f"DateOffset加1个月: {dt_offset}")
dt_timedelta = dt + timedelta(days=30) print(f"Timedelta加30天: {dt_timedelta}")
|
- 场景 2:工作日偏移(DateOffset 的专属能力)
1 2 3 4 5 6 7 8 9 10 11
| dt_fri = datetime(2024, 4, 5)
bday_offset = pd.offsets.BDay(1) dt_bday = dt_fri + bday_offset print(f"加1个工作日: {dt_bday}")
dt_1day = dt_fri + timedelta(days=1) print(f"加1天(Timedelta): {dt_1day}")
|
pd.offsets和pd.DateOffset区别
- 给指定日期(2024-01-31)加 1 个月和 2 天
1 2 3
| pd.Timestamp("2024-01-31") + pd.DateOffset(months=1, days=2)
pd.Timestamp("2024-01-31") + pd.offsets.MonthEnd(1) + pd.offsets.Day(2)
|
- 给周五(2024-04-05)加 1 个工作日(应跳到下周一),给周一(2024-04-08)加 2 个工作日(应跳到周三)
1 2 3 4 5 6 7 8 9 10
| dt_fri = datetime(2024, 4, 5) dt_mon = datetime(2024, 4, 8)
dt_fri + pd.offsets.BDay(1) dt_mon + pd.offsets.BDay(2)
dt_fri + pd.DateOffset(days=1,weekday=0) dt_mon + pd.DateOffset(days=2)
|
1 2 3
| pd.Timestamp(2024, 1, 15) + pd.offsets.MonthEnd(1)
pd.Timestamp(2024, 1, 15) + pd.DateOffset(day=31)
|
- 给 2024-04-05(周五)跳到当周最后一天(周日)
1 2 3
| pd.Timestamp("2024-04-05") + pd.DateOffset(days=0,weekday=6)
pd.Timestamp("2024-04-05") + pd.offsets.Week(1,weekday=6)
|
offsets.WeekOfMonth:week=0代表是当月第一周
1 2 3 4
| pd.Timestamp('20260304') + pd.offsets.WeekOfMonth(week=0,weekday=0)
pd.Timestamp('20260304') + pd.offsets.WeekOfMonth(week=1,weekday=0)
|
相关查询
1 2 3 4 5 6
| i = pd.date_range("2018-04-09", periods=4, freq="2D 2h") ts = pd.DataFrame({"A": [1, 2, 3, 4]}, index=i)
ts.at_time("2:00")
ts.between_time("0:15", "2:45")
|
1 2 3 4 5 6 7 8 9 10 11 12 13
| pd.Timestamp("2014-01-02") + pd.offsets.MonthBegin(n=0)
pd.Timestamp("2014-01-02") + pd.offsets.MonthEnd(n=0)
pd.Timestamp("2014-01-01") + pd.offsets.MonthBegin(n=0)
pd.Timestamp("2014-01-31") + pd.offsets.MonthEnd(n=0)
pd.Timestamp("2014-01-02") + pd.offsets.MonthEnd(n=1)
pd.Timestamp("2014-01-31") + pd.offsets.MonthEnd(n=1)
|
np.timedelta64仅支持’W’, ‘D’, ‘h’, ‘m’, ‘s’, ‘ms’, ‘us’, ‘ns’等固定的日期单位
1 2 3 4
| idx = pd.to_timedelta([1,2,3],unit="d") / np.timedelta64(1,"h")
pd.to_timedelta([1, 2, 3], unit="d") / pd.Timedelta("1h")
|
理解pd.period
1 2 3 4 5 6 7
| p = pd.Period("2011", freq="Y-JAN")
p.start_time, p.end_time
p = pd.Period("2011Q4", freq="Q-MAR")
p.start_time, p.end_time
|
1 2 3 4 5 6
| p = pd.Period('2012-01', freq='2M') p + 2
p - 1
|
1 2 3 4
| p = pd.Period('2011', freq='Y-DEC')
p.asfreq("M", how="start") p.asfreq("M", how="end")
|
resample函数
closed:
- 类型:
{'right', 'left'}
- 说明:定义时间间隔的哪一端是关闭的
label:
- 类型:
{'right', 'left'}
- 说明:在时间间隔内标记的哪一端(即时间戳将代表区间的起点还是终点)
on:
- 类型:字符串
- 说明:指定时间序列的列名,适用于非索引的时间序列
level:
- 类型:整数或字符串
- 说明:当索引是多层索引时,可以指定级别进行重采样
origin:
- 类型:
{'epoch', 'start', 'start_day','end','end_day'} 或者 时间戳字符串
- 说明:用于设置时间偏移的起点
- ‘epoch’:’1970-01-01‘
- ‘start’:时序序列的第一个值
- ‘start_day’:时间序列的第一天的午夜
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| rng = pd.date_range('1/1/2012', periods=1000, freq='S') ts = pd.Series(np.random.randint(0, 500, len(rng)), index=rng)
ts.resample('5Min').sum() ''' 2012-01-01 00:00:00 74477 2012-01-01 00:05:00 74834 2012-01-01 00:10:00 76489 2012-01-01 00:15:00 25095 Freq: 5T, dtype: int64 '''
ts.resample('5Min', closed='right').mean() ts.resample('5Min', closed='left').mean()
ts.resample("5Min").ohlc()
''' open high low close 2012-01-01 00:00:00 84 499 5 435 2012-01-01 00:05:00 229 497 1 440 2012-01-01 00:10:00 171 499 1 201 2012-01-01 00:15:00 431 499 0 289 '''
|
1 2 3 4 5 6 7 8 9 10 11
| iv = pd.Interval(left=0, right=5, closed='right')
iv.length
3.5 in iv 5.5 in iv
year_2020 = pd.Interval(pd.Timestamp('2020-01-01 00:00:00'), pd.Timestamp('2021-01-01 00:00:00'), closed='left')
|
间隔部分重叠
1 2 3 4 5 6 7 8 9 10
| i1 = pd.Interval(0, 2) i2 = pd.Interval(1, 3) i1.overlaps(i2)
i3 = pd.Interval(4, 5) i1.overlaps(i3)
i4 = pd.Interval(0, 1, closed='both') i5 = pd.Interval(1, 2, closed='both') i4.overlaps(i5)
|
计算操作
1 2 3 4 5 6 7 8 9 10
| iv
shifted_iv = iv + 3 shifted_iv
extended_iv = iv * 10.0 extended_iv
|
pd.IntervalIndex创建
from_breaks()
from_arrays()
from_tuples()
interval_range()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| pd.IntervalIndex.from_breaks([1, 3, 6, 10], closed="both")
pd.IntervalIndex.from_arrays(left=[1, 3, 6, 10], right=[5, 4, 9, 11], closed="neither")
pd.IntervalIndex.from_tuples([(1, 5), (3, 4), (6, 9), (10, 11)], closed="neither")
pd.interval_range(start=1, end=5, periods=8,closed="left") """ IntervalIndex([[1.0, 1.5), [1.5, 2.0), [2.0, 2.5), [2.5, 3.0), [3.0, 3.5), [3.5, 4.0), [4.0, 4.5), [4.5, 5.0)], dtype='interval[float64, left]') """
pd.interval_range(end=5, periods=8, freq=0.5)
|
方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| id_interval = pd.IntervalIndex(pd.cut(s, 3))
id_demo = id_interval[:5] ''' IntervalIndex([(33.945, 52.333], (52.333, 70.667], (70.667, 89.0], (33.945, 52.333], (70.667, 89.0]], dtype='interval[float64, right]', name='Weight') '''
id_demo.left id_demo.right id_demo.mid id_demo.length
id_demo.contains(4) id_demo.overlaps(pd.Interval(40,60))
|
文本处理
正则表达式
1 2 3
| reg, string = "Apple", "Apple! This Is an Apple!"
re.findall(reg, string)
|
元字符
集合元字符:用一个元字符来匹配某个字符的集合
| 语法 |
匹配对象 |
| . |
除换行符以外的所有字符 |
\w \W |
字母和数字、非字母和非数字 |
\d \D |
数字、非数字 |
\s \S |
空白字符(含空格“ ”、换行符“\n”、换页符“\f”、制表符“\t”)、非空白字符 |
[...] |
方括号内“…”中的任意一个字符 |
频次元字符:控制前面一个字符出现的次数
正则匹配默认使用贪婪模式,即尽可能长地匹配对应模式,如果一旦匹配到对应的正则表达式就停止匹配,可以在频次元字符后加“?”,将贪婪模式切换为懒惰模式
| 语法 |
匹配对象 |
? |
出现0 次或1 次 |
* |
出现0 次或0 次以上 |
+ |
出现1 次或1 次以上 |
{n} |
出现n 次 |
{n,} |
出现n 次或n 次以上 |
{n,m} |
出现n~m 次 |
逻辑元字符:主要指“|”表示的选择符号以及方括号集合匹配中“ˆ”表示的取反符号
1 2 3
| re.findall("ab|cd", "abc bcd acd")
re.findall("a[^\w!]", "a ab a? a!")
|
位置元字符:不匹配任何元素而是匹配位置,这里的位置包括单词的起始或终止、字符串的起始或终止
^和$针对整个字符串的开头 / 结尾(而非单词的开头 / 结尾)
| 语法 |
匹配位置 |
\b |
单词的起始或终止 |
\B |
不是单词的起始或终止 |
^ |
字符串的起始 |
$ |
字符串的终止 |
1 2 3
| re.findall(r"\BAB|cc\b", "CAB ccd AB cc AC")
re.findall("^[Tt]able|ble$|Ble$", "Table Table table taBle")
|
分组捕获与反向引用
1 2 3 4 5 6 7 8 9 10 11 12 13
| re.findall(r"(\w{3})-(\d{3})", "ABC-012 DEF-345")
re.findall(r"(?:\w{3})-(\d{3})", "ABC-012 DEF-345")
re.findall(r"(\w:\s)(\w+)\s\1(\w+)", "A: apple A: 苹果 B: banana B: 香蕉")
re.findall(r"(\d)(\1)(\2{0,2})", "11222333344444")
|
re.sub:正则替换
1 2 3 4 5
| re.sub(r"\d", "*", "1f93fdf0wef")
re.sub("\d", "", "1f93fdf0wef")
re.sub("([a-zA-Z])t", r"\1\1", "atjsjtjst")
|
零宽断言
| 名称 |
语法 |
功能 |
| 正向先行断言 |
(?=...) |
匹配…表达式的起始位置 |
| 正向后行断言 |
(?<=...) |
匹配…表达式的终止位置 |
| 负向先行断言 |
(?!...) |
匹配非…表达式的起始位置 |
| 负向后行断言 |
(?<!...) |
匹配非…表达式的终止位置 |
1 2 3 4 5 6 7
| re.findall(r":(\d+)(?=件)", "商品成交量:758件")
re.findall(r"(?<=成交量:)(\d+)", "商品成交量:758 件")
re.findall(r"(\d+)(?![件|\d])", "交易量减少50件,交易额增加100元")
re.findall(r"(?<![少|\d])(\d+)", "交易量减少50件,交易额增加100元")
|
优先级
| 运算符(优先级由高到低) |
描述 |
| \ |
转义符 |
| (), (?:), (?=), [] |
圆括号和方括号 |
| *, +, ?, {n}, {n,}, {n,m} |
限定符 |
| ^, $, \任何元字符、任何字符 |
定位点和序列(即:位置和顺序) |
| | |
替换,”或”操作 字符具有高于替换运算符的优先级,使得”m|food”匹配”m”或”food” |
特殊情况:使用str 对象的必要条件是序列中能够被索引或切片
1 2 3 4 5 6 7 8 9 10
| s = pd.Series([{1: "temp_1", 2: "temp_2"}, ["a", "b"], 0.5, "my_string"])
s.str[1] ''' 0 temp_1 1 b 2 NaN 3 y dtype: object '''
|
1 2 3 4 5 6 7 8 9 10 11 12
| s2 = pd.Series(['a_b_c', 'c_d_e', np.nan, 'f_g_h'], dtype="string")
s2.str.split('_', expand=True, n=1)
''' 0 1 0 a b_c 1 c d_e 2 <NA> <NA> 3 f g_h '''
|
使用正则
1 2
| s = pd.Series(["1+1=2"]) s.str.split(r"\+|=", expand=True)
|
划分:将文本按分隔符号划分为三个部分,保留分隔符
1 2 3 4 5 6 7 8 9
| s = pd.Series(['Linda van der Berg', 'George Pitt-Rivers'])
s.str.partition("-")
''' 0 1 2 0 Linda van der Berg 1 George Pitt - Rivers '''
|
1 2 3
| s = pd.Series(["12", "-$10", "$10,000"], dtype="string")
s.str.replace("$","")
|
使用正则
group参数理解
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| ( pd.Series(["foo", "fuz", np.nan]) .str.replace(r"[a-z]+", lambda m: m.group(0)[::-1],regex=True) ) ''' 0 oof 1 zuf 2 NaN dtype: object '''
pat = r"(?P<one>\w+) (?P<two>\w+) (?P<three>\w+)" repl = lambda m: m.group("two").swapcase() pd.Series(["One Two Three", "Foo Bar Baz"]).str.replace(pat, repl,regex=True) """ 0 tWO 1 bAR dtype: object """
|
指定替换
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| s = pd.Series(['a', 'ab', 'abc', 'abdc', 'abcde'])
s.str.slice_replace(1, repl='X') ''' 0 aX 1 aX 2 aX 3 aX 4 aX dtype: object '''
s.str.slice_replace(stop=2, repl='X') ''' 0 X 1 X 2 Xc 3 Xdc 4 Xcde dtype: object '''
s.str.slice_replace(start=1, stop=3, repl='X') ''' 0 aX 1 aX 2 aX 3 aXc 4 aXde dtype: object '''
|
重复替换
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| pd.Series(['a', 'b', 'c']).repeat(repeats=2)
pd.Series(['a', 'b', 'c']).str.repeat(repeats=2)
pd.Series(['a', 'b', 'c']).str.repeat(repeats=[1, 2, 3]) ''' 0 a 1 bb 2 ccc dtype: object '''
|
str.cat
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| s = pd.Series(['a', 'b', 'c', 'd'], dtype="string") s.str.cat(sep=',') s.str.cat()
t = pd.Series(['a', 'b', np.nan, 'd'], dtype="string") t.str.cat(sep=',') t.str.cat(sep=',', na_rep='-')
s.str.cat(['A', 'B', 'C', 'D']) ''' 0 aA 1 bB 2 cC 3 dD dtype: string '''
|
str.join
1 2 3 4 5 6 7 8 9
| s = pd.Series(["aaa","bb","c"])
s.str.join("-") ''' 0 a-a-a 1 b-b 2 c dtype: object '''
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| (pd.Series(['a1', 'b2', 'c3'], dtype="string") .str .extract(r'([ab])(\d)', expand=True) ) ''' 0 1 0 a 1 1 b 2 2 <NA> <NA> '''
s.str.extract(r'(?P<letter>[ab])(?P<digit>\d)') ''' letter digit 0 a 1 1 b 2 2 NaN NaN '''
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| s = pd.Series(["a1a2", "b1b7", "c1"], index=["A", "B", "C"], dtype="string") two_groups = '(?P<letter>[a-z])(?P<digit>[0-9])'
s.str.extractall(two_groups) ''' letter digit match A 0 a 1 1 a 2 B 0 b 1 1 b 7 C 0 c 1 '''
|
1 2 3 4 5 6 7 8
| s.str.count('a')
s.str.count(r'a|b|c')
s.str.len()
|
1 2 3 4 5 6 7 8
| s.str.isalpha() s.str.isalnum()
s.str.isdecimal() s.str.isdigit() s.str.isnumeric()
|
样式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| df.style.highlight_null(color="red",subset=["team"]) df.style.highlight_null(props="font-weight:700;color:red")
( df.head(10).style .highlight_max(subset=pd.IndexSlice[:10,"Q1":"Q4"], color="green", axis=1) .highlight_min(subset=pd.IndexSlice[:10,"Q1":"Q4"],axis=1,props="background-color:yellow;") )
df.style.highlight_between(subset=pd.IndexSlice[:,"Q1":"Q4"],left=10,right=90,color="yellow",axis=1,inclusive="both")
df = pd.DataFrame(np.arange(10).reshape(2,5) + 1)
df.style.highlight_quantile(axis=None, q_left=0.25, color="#fffd75")
df.style.highlight_quantile(axis=1, q_left=0.8, color="#fffd75")
|
色彩映射参考-cmap
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
|
df = pd.DataFrame(columns=["City", "Temp (c)", "Rain (mm)", "Wind (m/s)"], data=[["Stockholm", 21.6, 5.0, 3.2], ["Oslo", 22.4, 13.3, 3.1], ["Copenhagen", 24.5, 0.0, 6.7]])
df.style.text_gradient(axis=0)
df.style.text_gradient(axis=None)
df.style.text_gradient(axis=None, low=0.75, high=1.0)
df.style.text_gradient(axis=None, vmin=6.7, vmax=21.6)
( df.head(15) .style.background_gradient(subset=["Q1"], cmap="spring") .background_gradient(subset=["Q2"], vmin=60, vmax=100) .background_gradient(subset=["Q3"], low=0.6, high=0) .background_gradient(subset=["Q4"], text_color_threshold=0.9) )
df.style.bar(subset=['Q1'])
df.style.bar(color='green') df.style.bar(color='#ff11bb')
df.style.bar(axis=1)
df.style.bar(width=80)
df.style.bar(align='mid')
df.style.bar(vmin=60, vmax=100)
|
Python格式化字符串
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| name_1 = "tom" name_2 = "lily"
print(f"{name_1:5}100分") print(f"{name_2:5}100分")
print(f"{name_1:>08}") print(f"{name_1:<08}") print(f"{name_1:^08}")
f'今年{age:08}岁'
print(f'最高{8848:+}m') print(f'最低{-11043: }m')
a = 123.456 f'a is {a:.2f}'
f'a is {a:8.2f}'
f'a is {a:08.2f}'
f'a is {a:8.2%}'
f'a is {3253547568.43:,f}'
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| df.style.format("{:.2%}")
df.style.format({'name': str.upper})
df.style.format({'B': "{:0<4.0f}", 'D': '{:+.2f}'})
df.style.format({"B": lambda x: "±{:.2f}".format(abs(x))})
df.style.format("{:.2%}", na_rep="-")
df.style.format(na_rep='MISS', precision=3)
df.style.format('<a href="a.com/{0}">{0}</a>', escape="html")
df.loc[:,'Q2':].astype(float).style.format(decimal=';')
df.style.highlight_max().format(None, na_rep="-")
|
注意事项:新版本的pandas中不能链式调用format会导致覆盖(而不是合并),需要将所有的格式化放置于一个字典中
1 2 3 4 5 6 7 8
| (df.head(15) .head(10) .assign(avg=df.mean(axis=1, numeric_only=True)/100) .assign(diff=lambda x: x.avg.diff()) .style .format({'name': str.upper,'avg': "{:.2%}",'diff': "¥{:.2f}"}, na_rep="-") )
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| df.style.set_caption('学生成绩表')
df.style.set_properties(subset=['Q1'], **{'color': 'red'})
df.style.set_properties(color="white", align="right") df.style.set_properties(**{'background-color': 'yellow'}) df.style.set_properties(**{'width': '100px', 'font-size': '18px'}) df.style.set_properties(**{'background-color': 'black', 'color': 'lawngreen', 'border-color': 'white'})
df.style.set_table_attributes('class="pure-table"') df.style.set_table_attributes('id="gairuo-table"')
df.style.set_table_styles( [{"selector": "tr:hover", "props": [("background-color", "yellow")]}] )
df.style.set_table_styles({ 'A': [{'selector': '', 'props': [('color', 'red')]}], 'B': [{'selector': 'td', 'props': [('color', 'blue')]}] }, overwrite=False)
df.style.set_table_styles({ 0: [{'selector': 'td:hover', 'props': [('font-size', '25px')]}] }, axis=1, overwrite=False)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| def highlight_max(x): return ['color: red' if v == x.max() else '' for v in x]
df.style.apply(highlight_max)
df.loc[:,'Q1':'Q4'].style.apply(highlight_max, axis=1)
yellow_css = 'background-color: yellow' sfun = lambda x: [yellow_css]*len(x) if x.math > 80 else ['']*len(x) (df.style .apply(sfun, axis=1) )
yellow_css = "background-color: yellow" sfun = lambda x: yellow_css if type(x) == int and x > 90 else "" (df.style.map(sfun))
|
subset 可传入索引器 pd.IndexSlice实现复杂逻辑下的部分区域应用
1 2 3 4 5 6 7 8 9 10
| sst1 = pd.IndexSlice[df.loc[(df.c=='good') & (df.f>60)].index, 'f']
sfun1 = lambda x: 'background-color: yellow' if x > 500 else ''
( df.style .map(sfun1, subset=sst1)
)
|
样式复用/清除
1 2 3 4 5 6 7 8 9 10 11
| style1 = df.style.map(color_negative_red)
style2 = df2.style
style2.use(style1.export())
dfs = df.loc[:,'Q1':'Q4'].style.apply(highlight_max) dfs.clear() dfs
|