Python 数据分析(PYDA)第三版(五)(1)https://developer.aliyun.com/article/1482387
示例:随机抽样和排列
假设您想要从大型数据集中随机抽取(有或没有替换)用于蒙特卡洛模拟或其他应用。有许多执行“抽取”的方法;在这里,我们使用 Series 的sample
方法。
为了演示,这里有一种构建一副英式扑克牌的方法:
suits = ["H", "S", "C", "D"] # Hearts, Spades, Clubs, Diamonds card_val = (list(range(1, 11)) + [10] * 3) * 4 base_names = ["A"] + list(range(2, 11)) + ["J", "K", "Q"] cards = [] for suit in suits: cards.extend(str(num) + suit for num in base_names) deck = pd.Series(card_val, index=cards)
现在我们有一个长度为 52 的 Series,其索引包含牌名,值是在二十一点和其他游戏中使用的值(为了简单起见,我让 ace "A"
为 1):
In [122]: deck.head(13) Out[122]: AH 1 2H 2 3H 3 4H 4 5H 5 6H 6 7H 7 8H 8 9H 9 10H 10 JH 10 KH 10 QH 10 dtype: int64
现在,根据我之前说的,从牌组中抽取五张牌可以写成:
In [123]: def draw(deck, n=5): .....: return deck.sample(n) In [124]: draw(deck) Out[124]: 4D 4 QH 10 8S 8 7D 7 9C 9 dtype: int64
假设你想要从每种花色中抽取两张随机牌。因为花色是每张牌名称的最后一个字符,我们可以根据这个进行分组,并使用apply
:
In [125]: def get_suit(card): .....: # last letter is suit .....: return card[-1] In [126]: deck.groupby(get_suit).apply(draw, n=2) Out[126]: C 6C 6 KC 10 D 7D 7 3D 3 H 7H 7 9H 9 S 2S 2 QS 10 dtype: int64
或者,我们可以传递group_keys=False
以删除外部套索索引,只留下所选的卡:
In [127]: deck.groupby(get_suit, group_keys=False).apply(draw, n=2) Out[127]: AC 1 3C 3 5D 5 4D 4 10H 10 7H 7 QS 10 7S 7 dtype: int64
示例:组加权平均和相关性
在groupby
的分割-应用-组合范式下,DataFrame 或两个 Series 中的列之间的操作,例如组加权平均,是可能的。例如,考虑包含组键、值和一些权重的数据集:
In [128]: df = pd.DataFrame({"category": ["a", "a", "a", "a", .....: "b", "b", "b", "b"], .....: "data": np.random.standard_normal(8), .....: "weights": np.random.uniform(size=8)}) In [129]: df Out[129]: category data weights 0 a -1.691656 0.955905 1 a 0.511622 0.012745 2 a -0.401675 0.137009 3 a 0.968578 0.763037 4 b -1.818215 0.492472 5 b 0.279963 0.832908 6 b -0.200819 0.658331 7 b -0.217221 0.612009
按category
加权平均值将是:
In [130]: grouped = df.groupby("category") In [131]: def get_wavg(group): .....: return np.average(group["data"], weights=group["weights"]) In [132]: grouped.apply(get_wavg) Out[132]: category a -0.495807 b -0.357273 dtype: float64
另一个例子是,考虑一个最初从 Yahoo! Finance 获取的金融数据集,其中包含一些股票的日终价格和标准普尔 500 指数(SPX
符号):
In [133]: close_px = pd.read_csv("examples/stock_px.csv", parse_dates=True, .....: index_col=0) In [134]: close_px.info() <class 'pandas.core.frame.DataFrame'> DatetimeIndex: 2214 entries, 2003-01-02 to 2011-10-14 Data columns (total 4 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 AAPL 2214 non-null float64 1 MSFT 2214 non-null float64 2 XOM 2214 non-null float64 3 SPX 2214 non-null float64 dtypes: float64(4) memory usage: 86.5 KB In [135]: close_px.tail(4) Out[135]: AAPL MSFT XOM SPX 2011-10-11 400.29 27.00 76.27 1195.54 2011-10-12 402.19 26.96 77.16 1207.25 2011-10-13 408.43 27.18 76.37 1203.66 2011-10-14 422.00 27.27 78.11 1224.58
这里的 DataFrame info()
方法是获取 DataFrame 内容概述的便捷方式。
一个感兴趣的任务可能是计算一个由每日收益(从百分比变化计算)与SPX
的年度相关性组成的 DataFrame。作为一种方法,我们首先创建一个函数,计算每列与"SPX"
列的成对相关性:
In [136]: def spx_corr(group): .....: return group.corrwith(group["SPX"])
接下来,我们使用pct_change
计算close_px
的百分比变化:
In [137]: rets = close_px.pct_change().dropna()
最后,我们按年将这些百分比变化分组,可以使用一个一行函数从每个行标签中提取datetime
标签的year
属性:
In [138]: def get_year(x): .....: return x.year In [139]: by_year = rets.groupby(get_year) In [140]: by_year.apply(spx_corr) Out[140]: AAPL MSFT XOM SPX 2003 0.541124 0.745174 0.661265 1.0 2004 0.374283 0.588531 0.557742 1.0 2005 0.467540 0.562374 0.631010 1.0 2006 0.428267 0.406126 0.518514 1.0 2007 0.508118 0.658770 0.786264 1.0 2008 0.681434 0.804626 0.828303 1.0 2009 0.707103 0.654902 0.797921 1.0 2010 0.710105 0.730118 0.839057 1.0 2011 0.691931 0.800996 0.859975 1.0
您还可以计算列间的相关性。这里我们计算苹果和微软之间的年度相关性:
In [141]: def corr_aapl_msft(group): .....: return group["AAPL"].corr(group["MSFT"]) In [142]: by_year.apply(corr_aapl_msft) Out[142]: 2003 0.480868 2004 0.259024 2005 0.300093 2006 0.161735 2007 0.417738 2008 0.611901 2009 0.432738 2010 0.571946 2011 0.581987 dtype: float64
示例:组内线性回归
与前面的示例相同,您可以使用groupby
执行更复杂的组内统计分析,只要函数返回一个 pandas 对象或标量值。例如,我可以定义以下regress
函数(使用statsmodels
计量经济学库),它在每个数据块上执行普通最小二乘(OLS)回归:
import statsmodels.api as sm def regress(data, yvar=None, xvars=None): Y = data[yvar] X = data[xvars] X["intercept"] = 1. result = sm.OLS(Y, X).fit() return result.params
如果您尚未安装statsmodels
,可以使用 conda 安装它:
conda install statsmodels
现在,要在AAPL
对SPX
回报的年度线性回归中执行:
In [144]: by_year.apply(regress, yvar="AAPL", xvars=["SPX"]) Out[144]: SPX intercept 2003 1.195406 0.000710 2004 1.363463 0.004201 2005 1.766415 0.003246 2006 1.645496 0.000080 2007 1.198761 0.003438 2008 0.968016 -0.001110 2009 0.879103 0.002954 2010 1.052608 0.001261 2011 0.806605 0.001514
10.4 组转换和“展开”的 GroupBys
在 Apply: General split-apply-combine 中,我们看了一下在分组操作中执行转换的apply
方法。还有另一个内置方法叫做transform
,它类似于apply
,但对您可以使用的函数种类施加了更多的约束:
- 它可以生成一个标量值广播到组的形状。
- 它可以生成与输入组相同形状的对象。
- 它不能改变其输入。
让我们考虑一个简单的例子以说明:
In [145]: df = pd.DataFrame({'key': ['a', 'b', 'c'] * 4, .....: 'value': np.arange(12.)}) In [146]: df Out[146]: key value 0 a 0.0 1 b 1.0 2 c 2.0 3 a 3.0 4 b 4.0 5 c 5.0 6 a 6.0 7 b 7.0 8 c 8.0 9 a 9.0 10 b 10.0 11 c 11.0
这里是按键的组平均值:
In [147]: g = df.groupby('key')['value'] In [148]: g.mean() Out[148]: key a 4.5 b 5.5 c 6.5 Name: value, dtype: float64
假设我们想要生成一个与df['value']
相同形状的 Series,但值被按'key'
分组后的平均值替换。我们可以传递一个计算单个组平均值的函数给transform
:
In [149]: def get_mean(group): .....: return group.mean() In [150]: g.transform(get_mean) Out[150]: 0 4.5 1 5.5 2 6.5 3 4.5 4 5.5 5 6.5 6 4.5 7 5.5 8 6.5 9 4.5 10 5.5 11 6.5 Name: value, dtype: float64
对于内置的聚合函数,我们可以像 GroupBy agg
方法一样传递一个字符串别名:
In [151]: g.transform('mean') Out[151]: 0 4.5 1 5.5 2 6.5 3 4.5 4 5.5 5 6.5 6 4.5 7 5.5 8 6.5 9 4.5 10 5.5 11 6.5 Name: value, dtype: float64
与apply
一样,transform
适用于返回 Series 的函数,但结果必须与输入的大小相同。例如,我们可以使用一个辅助函数将每个组乘以 2:
In [152]: def times_two(group): .....: return group * 2 In [153]: g.transform(times_two) Out[153]: 0 0.0 1 2.0 2 4.0 3 6.0 4 8.0 5 10.0 6 12.0 7 14.0 8 16.0 9 18.0 10 20.0 11 22.0 Name: value, dtype: float64
作为一个更复杂的例子,我们可以计算每个组按降序排名:
In [154]: def get_ranks(group): .....: return group.rank(ascending=False) In [155]: g.transform(get_ranks) Out[155]: 0 4.0 1 4.0 2 4.0 3 3.0 4 3.0 5 3.0 6 2.0 7 2.0 8 2.0 9 1.0 10 1.0 11 1.0 Name: value, dtype: float64
考虑一个由简单聚合组成的组转换函数:
In [156]: def normalize(x): .....: return (x - x.mean()) / x.std()
在这种情况下,我们可以使用transform
或apply
获得等效的结果:
In [157]: g.transform(normalize) Out[157]: 0 -1.161895 1 -1.161895 2 -1.161895 3 -0.387298 4 -0.387298 5 -0.387298 6 0.387298 7 0.387298 8 0.387298 9 1.161895 10 1.161895 11 1.161895 Name: value, dtype: float64 In [158]: g.apply(normalize) Out[158]: key a 0 -1.161895 3 -0.387298 6 0.387298 9 1.161895 b 1 -1.161895 4 -0.387298 7 0.387298 10 1.161895 c 2 -1.161895 5 -0.387298 8 0.387298 11 1.161895 Name: value, dtype: float64
内置的聚合函数如'mean'
或'sum'
通常比一般的apply
函数快得多。当与transform
一起使用时,这些函数也有一个“快速路径”。这使我们能够执行所谓的展开组操作:
In [159]: g.transform('mean') Out[159]: 0 4.5 1 5.5 2 6.5 3 4.5 4 5.5 5 6.5 6 4.5 7 5.5 8 6.5 9 4.5 10 5.5 11 6.5 Name: value, dtype: float64 In [160]: normalized = (df['value'] - g.transform('mean')) / g.transform('std') In [161]: normalized Out[161]: 0 -1.161895 1 -1.161895 2 -1.161895 3 -0.387298 4 -0.387298 5 -0.387298 6 0.387298 7 0.387298 8 0.387298 9 1.161895 10 1.161895 11 1.161895 Name: value, dtype: float64
在这里,我们在多个 GroupBy 操作的输出之间进行算术运算,而不是编写一个函数并将其传递给groupby(...).apply
。这就是所谓的“展开”。
尽管展开的组操作可能涉及多个组聚合,但矢量化操作的整体效益通常超过了这一点。
10.5 透视表和交叉制表
透视表是一种经常在电子表格程序和其他数据分析软件中找到的数据汇总工具。它通过一个或多个键对数据表进行聚合,将数据排列在一个矩形中,其中一些组键沿行排列,另一些沿列排列。在 Python 中,通过本章描述的groupby
功能以及利用分层索引进行重塑操作,可以实现使用 pandas 的透视表。DataFrame 还有一个pivot_table
方法,还有一个顶级的pandas.pivot_table
函数。除了提供一个方便的groupby
接口外,pivot_table
还可以添加部分总计,也称为边际。
返回到小费数据集,假设您想要计算按day
和smoker
排列的组平均值的表格(默认的pivot_table
聚合类型):
In [162]: tips.head() Out[162]: total_bill tip smoker day time size tip_pct 0 16.99 1.01 No Sun Dinner 2 0.059447 1 10.34 1.66 No Sun Dinner 3 0.160542 2 21.01 3.50 No Sun Dinner 3 0.166587 3 23.68 3.31 No Sun Dinner 2 0.139780 4 24.59 3.61 No Sun Dinner 4 0.146808 In [163]: tips.pivot_table(index=["day", "smoker"], .....: values=["size", "tip", "tip_pct", "total_bill"]) Out[163]: size tip tip_pct total_bill day smoker Fri No 2.250000 2.812500 0.151650 18.420000 Yes 2.066667 2.714000 0.174783 16.813333 Sat No 2.555556 3.102889 0.158048 19.661778 Yes 2.476190 2.875476 0.147906 21.276667 Sun No 2.929825 3.167895 0.160113 20.506667 Yes 2.578947 3.516842 0.187250 24.120000 Thur No 2.488889 2.673778 0.160298 17.113111 Yes 2.352941 3.030000 0.163863 19.190588
这可以直接使用groupby
生成,使用tips.groupby(["day", "smoker"]).mean()
。现在,假设我们只想计算tip_pct
和size
的平均值,并另外按time
分组。我将smoker
放在表格列中,time
和day
放在行中:
In [164]: tips.pivot_table(index=["time", "day"], columns="smoker", .....: values=["tip_pct", "size"]) Out[164]: size tip_pct smoker No Yes No Yes time day Dinner Fri 2.000000 2.222222 0.139622 0.165347 Sat 2.555556 2.476190 0.158048 0.147906 Sun 2.929825 2.578947 0.160113 0.187250 Thur 2.000000 NaN 0.159744 NaN Lunch Fri 3.000000 1.833333 0.187735 0.188937 Thur 2.500000 2.352941 0.160311 0.163863
我们可以通过传递margins=True
来增加此表,以包括部分总计。这将添加All
行和列标签,相应的值是单个层次内所有数据的组统计信息:
In [165]: tips.pivot_table(index=["time", "day"], columns="smoker", .....: values=["tip_pct", "size"], margins=True) Out[165]: size tip_pct smoker No Yes All No Yes All time day Dinner Fri 2.000000 2.222222 2.166667 0.139622 0.165347 0.158916 Sat 2.555556 2.476190 2.517241 0.158048 0.147906 0.153152 Sun 2.929825 2.578947 2.842105 0.160113 0.187250 0.166897 Thur 2.000000 NaN 2.000000 0.159744 NaN 0.159744 Lunch Fri 3.000000 1.833333 2.000000 0.187735 0.188937 0.188765 Thur 2.500000 2.352941 2.459016 0.160311 0.163863 0.161301 All 2.668874 2.408602 2.569672 0.159328 0.163196 0.160803
这里,All
值是没有考虑吸烟者与非吸烟者(All
列)或行中的两个级别分组的平均值(All
行)。
要使用除mean
之外的聚合函数,请将其传递给aggfunc
关键字参数。例如,"count"
或len
将为您提供组大小的交叉制表(计数或频率)(尽管"count"
将在数据组内排除空值的计数,而len
不会):
In [166]: tips.pivot_table(index=["time", "smoker"], columns="day", .....: values="tip_pct", aggfunc=len, margins=True) Out[166]: day Fri Sat Sun Thur All time smoker Dinner No 3.0 45.0 57.0 1.0 106 Yes 9.0 42.0 19.0 NaN 70 Lunch No 1.0 NaN NaN 44.0 45 Yes 6.0 NaN NaN 17.0 23 All 19.0 87.0 76.0 62.0 244
如果某些组合为空(或其他 NA),您可能希望传递一个fill_value
:
In [167]: tips.pivot_table(index=["time", "size", "smoker"], columns="day", .....: values="tip_pct", fill_value=0) Out[167]: day Fri Sat Sun Thur time size smoker Dinner 1 No 0.000000 0.137931 0.000000 0.000000 Yes 0.000000 0.325733 0.000000 0.000000 2 No 0.139622 0.162705 0.168859 0.159744 Yes 0.171297 0.148668 0.207893 0.000000 3 No 0.000000 0.154661 0.152663 0.000000 ... ... ... ... ... Lunch 3 Yes 0.000000 0.000000 0.000000 0.204952 4 No 0.000000 0.000000 0.000000 0.138919 Yes 0.000000 0.000000 0.000000 0.155410 5 No 0.000000 0.000000 0.000000 0.121389 6 No 0.000000 0.000000 0.000000 0.173706 [21 rows x 4 columns]
请参阅表 10.2 以获取pivot_table
选项的摘要。
表 10.2:pivot_table
选项
参数 | 描述 |
values |
要聚合的列名;默认情况下,聚合所有数值列 |
index |
要在生成的透视表的行上分组的列名或其他组键 |
columns |
要在生成的透视表的列上分组的列名或其他组键 |
aggfunc |
聚合函数或函数列表(默认为"mean" );可以是在groupby 上下文中有效的任何函数 |
fill_value |
替换结果表中的缺失值 |
dropna |
如果为True ,则不包括所有条目都为NA 的列 |
margins |
添加行/列小计和总计(默认为False ) |
margins_name |
在传递margins=True 时用于边缘行/列标签的名称;默认为"All" |
observed |
使用分类组键,如果为True ,则仅显示键中的观察类别值,而不是所有类别 |
交叉制表:交叉制表
交叉制表(或简称为交叉制表)是计算组频率的透视表的一种特殊情况。这里是一个例子:
In [168]: from io import StringIO In [169]: data = """Sample Nationality Handedness .....: 1 USA Right-handed .....: 2 Japan Left-handed .....: 3 USA Right-handed .....: 4 Japan Right-handed .....: 5 Japan Left-handed .....: 6 Japan Right-handed .....: 7 USA Right-handed .....: 8 USA Left-handed .....: 9 Japan Right-handed .....: 10 USA Right-handed""" .....: In [170]: data = pd.read_table(StringIO(data), sep="\s+")
In [171]: data Out[171]: Sample Nationality Handedness 0 1 USA Right-handed 1 2 Japan Left-handed 2 3 USA Right-handed 3 4 Japan Right-handed 4 5 Japan Left-handed 5 6 Japan Right-handed 6 7 USA Right-handed 7 8 USA Left-handed 8 9 Japan Right-handed 9 10 USA Right-handed
作为一些调查分析的一部分,我们可能希望按国籍和惯用手总结这些数据。您可以使用pivot_table
来做到这一点,但pandas.crosstab
函数可能更方便:
In [172]: pd.crosstab(data["Nationality"], data["Handedness"], margins=True) Out[172]: Handedness Left-handed Right-handed All Nationality Japan 2 3 5 USA 1 4 5 All 3 7 10
crosstab
的前两个参数可以是数组、Series 或数组列表。就像在小费数据中一样:
In [173]: pd.crosstab([tips["time"], tips["day"]], tips["smoker"], margins=True) Out[173]: smoker No Yes All time day Dinner Fri 3 9 12 Sat 45 42 87 Sun 57 19 76 Thur 1 0 1 Lunch Fri 1 6 7 Thur 44 17 61 All 151 93 244
10.6 结论
掌握 pandas 的数据分组工具可以帮助数据清洗和建模或统计分析工作。在 Ch 13:数据分析示例中,我们将查看几个更多实际数据上使用groupby
的示例用例。
在下一章中,我们将把注意力转向时间序列数据。
十一、时间序列
原文:
wesmckinney.com/book/time-series
译者:飞龙
此开放访问网络版本的《Python 数据分析第三版》现已作为印刷版和数字版的伴侣提供。如果您发现任何勘误,请在此处报告。请注意,由 Quarto 生成的本站点的某些方面与 O’Reilly 的印刷版和电子书版本的格式不同。
如果您发现本书的在线版本有用,请考虑订购纸质版或无 DRM 的电子书以支持作者。本网站的内容不得复制或再生产。代码示例采用 MIT 许可,可在 GitHub 或 Gitee 上找到。
时间序列数据是许多不同领域中的结构化数据的重要形式,如金融、经济、生态学、神经科学和物理学。任何在许多时间点重复记录的东西都构成一个时间序列。许多时间序列是固定频率的,也就是说,数据点按照某种规则定期发生,例如每 15 秒、每 5 分钟或每月一次。时间序列也可以是不规则的,没有固定的时间单位或单位之间的偏移。如何标记和引用时间序列数据取决于应用程序,您可能有以下之一:
时间戳
特定的时间点。
固定周期
例如 2017 年 1 月的整个月,或 2020 年的整年。
时间间隔
由开始和结束时间戳指示。周期可以被视为间隔的特殊情况。
实验或经过的时间
每个时间戳都是相对于特定开始时间的时间度量(例如,自放入烤箱以来每秒烘烤的饼干的直径),从 0 开始。
在本章中,我主要关注前三类时间序列,尽管许多技术也可以应用于实验时间序列,其中索引可能是整数或浮点数,表示从实验开始经过的时间。最简单的时间序列是由时间戳索引的。
提示:
pandas 还支持基于时间差的索引,这是一种表示实验或经过时间的有用方式。我们在本书中没有探讨时间差索引,但您可以在pandas 文档中了解更多。
pandas 提供了许多内置的时间序列工具和算法。您可以高效地处理大型时间序列,对不规则和固定频率的时间序列进行切片、聚合和重采样。其中一些工具对金融和经济应用很有用,但您当然也可以用它们来分析服务器日志数据。
与其他章节一样,我们首先导入 NumPy 和 pandas:
In [12]: import numpy as np In [13]: import pandas as pd
11.1 日期和时间数据类型和工具
Python 标准库包括用于日期和时间数据以及与日历相关的功能的数据类型。datetime
、time
和calendar
模块是主要的起点。datetime.datetime
类型,或简称datetime
,被广泛使用:
In [14]: from datetime import datetime In [15]: now = datetime.now() In [16]: now Out[16]: datetime.datetime(2023, 4, 12, 13, 9, 16, 484533) In [17]: now.year, now.month, now.day Out[17]: (2023, 4, 12)
datetime
存储日期和时间,精确到微秒。datetime.timedelta
,或简称timedelta
,表示两个datetime
对象之间的时间差:
In [18]: delta = datetime(2011, 1, 7) - datetime(2008, 6, 24, 8, 15) In [19]: delta Out[19]: datetime.timedelta(days=926, seconds=56700) In [20]: delta.days Out[20]: 926 In [21]: delta.seconds Out[21]: 56700
您可以将timedelta
或其倍数添加(或减去)到datetime
对象中,以产生一个新的偏移对象:
In [22]: from datetime import timedelta In [23]: start = datetime(2011, 1, 7) In [24]: start + timedelta(12) Out[24]: datetime.datetime(2011, 1, 19, 0, 0) In [25]: start - 2 * timedelta(12) Out[25]: datetime.datetime(2010, 12, 14, 0, 0)
表 11.1 总结了datetime
模块中的数据类型。虽然本章主要关注 pandas 中的数据类型和高级时间序列操作,但您可能会在 Python 的许多其他地方遇到基于datetime
的类型。
表 11.1:datetime
模块中的类型
类型 | 描述 |
date |
使用公历存储日期(年,月,日) |
time |
以小时,分钟,秒和微秒存储一天中的时间 |
datetime |
存储日期和时间 |
timedelta |
两个datetime 值之间的差异(以天,秒和微秒计) |
tzinfo |
存储时区信息的基本类型 |
在字符串和日期时间之间转换
您可以使用str
或strftime
方法对datetime
对象和 pandas 的Timestamp
对象进行格式化为字符串,传递格式规范:
In [26]: stamp = datetime(2011, 1, 3) In [27]: str(stamp) Out[27]: '2011-01-03 00:00:00' In [28]: stamp.strftime("%Y-%m-%d") Out[28]: '2011-01-03'
请参阅表 11.2 以获取完整的格式代码列表。
表 11.2:datetime
格式规范(ISO C89 兼容)
类型 | 描述 |
%Y |
四位数年份 |
%y |
两位数年份 |
%m |
两位数月份[01, 12] |
%d |
两位数日期[01, 31] |
%H |
小时(24 小时制)[00, 23] |
%I |
小时(12 小时制)[01, 12] |
%M |
两位数分钟[00, 59] |
%S |
秒[00, 61](秒 60, 61 表示闰秒) |
%f |
微秒作为整数,零填充(从 000000 到 999999) |
%j |
一年中的日期作为零填充的整数(从 001 到 336) |
%w |
星期几作为整数[0(星期日),6] |
%u |
从 1 开始的星期几整数,其中 1 是星期一。 |
%U |
一年中的周数[00, 53]; 星期日被认为是一周的第一天,年初第一个星期日之前的日子被称为“第 0 周” |
%W |
一年中的周数[00, 53]; 星期一被认为是一周的第一天,年初第一个星期一之前的日子被称为“第 0 周” |
%z |
UTC 时区偏移为+HHMM 或-HHMM ; 如果时区是 naive,则为空 |
%Z |
时区名称作为字符串,如果没有时区则为空字符串 |
%F |
%Y-%m-%d 的快捷方式(例如,2012-4-18 ) |
%D |
%m/%d/%y 的快捷方式(例如,04/18/12 ) |
您可以使用许多相同的格式代码使用datetime.strptime
将字符串转换为日期(但是一些代码,如%F
,不能使用):
In [29]: value = "2011-01-03" In [30]: datetime.strptime(value, "%Y-%m-%d") Out[30]: datetime.datetime(2011, 1, 3, 0, 0) In [31]: datestrs = ["7/6/2011", "8/6/2011"] In [32]: [datetime.strptime(x, "%m/%d/%Y") for x in datestrs] Out[32]: [datetime.datetime(2011, 7, 6, 0, 0), datetime.datetime(2011, 8, 6, 0, 0)]
datetime.strptime
是一种解析具有已知格式的日期的方法。
pandas 通常面向处理日期数组,无论是作为轴索引还是数据框中的列。pandas.to_datetime
方法解析许多不同类型的日期表示。标准日期格式如 ISO 8601 可以快速解析:
In [33]: datestrs = ["2011-07-06 12:00:00", "2011-08-06 00:00:00"] In [34]: pd.to_datetime(datestrs) Out[34]: DatetimeIndex(['2011-07-06 12:00:00', '2011-08-06 00:00:00'], dtype='dat etime64[ns]', freq=None)
它还处理应被视为缺失的值(None
,空字符串等):
In [35]: idx = pd.to_datetime(datestrs + [None]) In [36]: idx Out[36]: DatetimeIndex(['2011-07-06 12:00:00', '2011-08-06 00:00:00', 'NaT'], dty pe='datetime64[ns]', freq=None) In [37]: idx[2] Out[37]: NaT In [38]: pd.isna(idx) Out[38]: array([False, False, True])
NaT
(不是时间)是 pandas 中的时间戳数据的空值。
注意
dateutil.parser
是一个有用但不完美的工具。值得注意的是,它会将一些字符串识别为日期,而您可能希望它不会;例如,"42"
将被解析为年份2042
与今天的日历日期相对应。
datetime
对象还具有许多针对其他国家或语言系统的特定于区域的格式选项。例如,德国或法国系统上的缩写月份名称与英语系统上的不同。请参阅表 11.3 以获取列表。
表 11.3:特定于区域的日期格式化
类型 | 描述 |
%a |
缩写的星期几名称 |
%A |
完整的星期几名称 |
%b |
缩写的月份名称 |
%B |
完整的月份名称 |
%c |
完整的日期和时间(例如,‘周二 2012 年 5 月 1 日 下午 04:20:57’) |
%p |
AM 或 PM 的本地等效 |
%x |
本地适用的格式化日期(例如,在美国,2012 年 5 月 1 日为‘05/01/2012’) |
| %X
| 本地适用的时间(例如,‘下午 04:24:12’) |
Python 数据分析(PYDA)第三版(五)(3)https://developer.aliyun.com/article/1482393