Pandas

提示：此条目的主题不是PANDAS，它是用于Pandora Archive的澳大利亚归档管理系统。

pandas

原作者| Wes McKinney（英语：Wes McKinney）
開發者| 社区
首次发布| 2008年1月11日，​17年前​（2008-01-11）
当前版本| 2.3.1[1]（2025年7月7日，15天前）
源代码库|

* github.com/pandas-dev/pandas

编程语言| Python, Cython, C
操作系统| 跨平台
类型| 数据分析
许可协议| 三条款BSD许可证
网站| pandas.pydata.org

在计算机编程中，pandas是用于数据操纵和分析的Python软件库。它建造在NumPy基础上，并为操纵数值表格和时间序列，提供了数据结构和运算操作。它是在三条款BSD许可证下发行的自由软件[2]。它的名字衍生自术语“面板数据”（panel data），这是计量经济学的术语，即包括了对同一个体在某个时期内多个时间点的观测的数据集[3]。它的名字还可解释为对短语“Python data analysis”的玩笑[4]。

## 历史

[编辑]

2008年，原作者Wes McKinney（英语：Wes McKinney）开始在AQR资本管理公司制作pandas，用来满足在财务数据上进行定量分析（英语：Quantitative analysis (finance)）时，对高性能、灵活工具的需要。2009年，他在离开AQR之前，说服管理者允许他将这个软件库开放源代码。下面是其开发过程的时间线[5]：

* 2008年，pandas開發開始。
* 2009年，pandas開源。
* 2012年，另一个AQR雇员Chang She加入了这个项目，并成为这个软件库的第二个主要贡献者。第一版《Python for Data Analysis》發布。
* 2015年，pandas签约为NumFOCUS的一个财务赞助项目，NumFOCUS是美国的501(c)(3)非营利公益组织。
* 2018年，举行了第一次面對面的“核心開發者衝刺”。
* 2022年，第三版《Python for Data Analysis》公开版在线发行[6]。

## 数据模型

[编辑]

pandas的序列（`Series`）是一维的加标签数据结构，它能够持有任何数据类型，如整数、字符串、浮点数和Python对象等，轴标签在集体上称为索引（`index`）。序列表现得非常类似于NumPy的`ndarray`数据结构，并且是大多数NumPy函数的有效实际参数。

pandas提供了类似于R语言中`data.frame`对象的数据帧（`DataFrame`），它是二维的加标签数据结构，其诸纵列潜在的可能具有不同的类型；数据帧就像是电子表格或SQL表，或者是序列的字典[7]，这种格局也叫做数组之结构（英语：AoS_and_SoA）（SoA）。pandas允许各种数据操纵运算操作，比如选择[8]、归并[9]和重制形状[10]，还有数据清洗和数据加工（英语：data wrangling）特征。

## 主要特征

[编辑]

pandas提供了快速而高效的数据帧对象，用于凭借其集成的索引进行数据操纵。它的主要特征有：

* 易于将在其他的Python和NumPy数据结构中，参差不齐或不同索引的数据，转换成数据帧对象。
* 大小可变性，可以在数据帧和更高维对象中插入或删除纵列。
* 自动和显式的“数据对齐”，标签和数据之间的联系是固有的，但是可以显式的控制二元运算的匹配和广播行为[11]。两个序列对象按标签自动对齐，两个数据帧对象自动对齐于纵列标签和索引（即横行标签）二者上，二元运算的结果对象具有双方的纵列标签和横行标签的并集；数据帧与序列对象之间的默认行为，是序列的索引自动对齐于数据帧的纵列标签，从而纵向逐横行广播[12]。
* 易于处理缺失数据，它被表示为用于浮点数的`NaN`（即NumPy的`nan`）、用于日期时间的`NaT`或跨数据类型的`NA`[13]。
* 智能的对大数据集的基于标签的分片（英语：Array slicing），多重索引和其他花样索引，依据布尔值向量的子集化（英语：Subsetting）。
* 直观的数据集的归并和连接。
* 强大而灵活的分组（英语：Group by (SQL)）（`groupby`）功能，用来在数据集上进行分离-应用-合并（split-apply-combine）运算，它可用于数据聚合（英语：Aggregate function）和变换（英语：Data transformation (computing)）二者。
* 灵活的数据集的重制形状（reshape）和枢轴汇总。
* 轴可以有层级标签，从而在绘图时每个刻度可能有多重标签。
* 健壮的I/O工具，用于从CSV文件和其他平面文件、JSON文件、Parquet（英语：Apache Parquet）文件、Arrow的Feather文件、SQL表和查询、Excel文件装载数据，并以极快的HDF5格式保存/装载数据。[14]
* 特定于时间序列的功能，例如日期范围生成和频率转换，移动窗口统计比如移动平均，日期移位（英语：Shift operator）和滞后（英语：Lag operator）。

pandas经过了高度的性能优化，关键代码路径用Cython或C语言写成。pandas可以利用PyArrow来扩展功能并增进各种API的性能[15]。pandas的缺省绘图后端是matplotlib，还可以扩展上其他第三方绘图（英语：Plot (graphics)）后端[16]，比如Plotly Express[17]。 进程内（英语：Embedded database）SQL OLAP列式数据库DuckDB，可以在pandas数据帧上执行SQL[18]。

## 示例

[编辑]

### 基本运算

[编辑]

在下面的梗概示例中，展示针对数据帧的纵列和横行的基本运算：

>>> import pandas as pd
>>> import numpy as np
>>> import matplotlib.pyplot as plt
>>>
>>> data = {
...     'place': ['A']*3 + ['B']*3 + ['C']*3 + ['D']*3,
...     'date': pd.to_datetime(['2023-01-01', '2023-01-02', '2023-01-03'] * 4),
...     'value': [x + 0.1 for x in range(12)]
... }
>>>
>>> df = pd.DataFrame(data)
>>> type(df['value']) == pd.Series
True
>>>
>>> df['value1'] = df['value'] + 0.1
>>> df
place       date  value  value1
0      A 2023-01-01    0.1     0.2
1      A 2023-01-02    1.1     1.2
2      A 2023-01-03    2.1     2.2
3      B 2023-01-01    3.1     3.2
4      B 2023-01-02    4.1     4.2
5      B 2023-01-03    5.1     5.2
6      C 2023-01-01    6.1     6.2
7      C 2023-01-02    7.1     7.2
8      C 2023-01-03    8.1     8.2
9      D 2023-01-01    9.1     9.2
10     D 2023-01-02   10.1    10.2
11     D 2023-01-03   11.1    11.2
>>>
>>> df.index
RangeIndex(start=0, stop=12, step=1)
>>>
>>> df.columns
Index(['place', 'date', 'value', 'value1'], dtype='object')
>>>
>>> df.loc[[1, 2], ['value', 'value1']]
value  value1
1    1.1     1.2
2    2.1     2.2
>>>
>>> df.at[1, 'value']
1.1
>>>
>>> df['value'].loc[1]
1.1
>>>
>>> df[['value','value1']].to_numpy().mean().round(2)
np.float64(5.65)
>>> df[['value','value1']].to_numpy().mean(axis=0)
array([5.6, 5.7])
>>> df[['value','value1']].to_numpy().mean(axis=1)
array([ 0.15,  1.15,  2.15,  3.15,  4.15,  5.15,  6.15,  7.15,  8.15,
9.15, 10.15, 11.15])
>>>
>>> df[(df['value']/2 > 1) & (df['value1'] < 3)]
place       date  value  value1
2     A 2023-01-03    2.1     2.2
>>>
>>> df.query('value/2 > 1 & value1 < 3')
place       date  value  value1
2     A 2023-01-03    2.1     2.2
>>>
>>> df[df['value'] == 1.1]['value1'].round(2).item()
1.2
>>>

### 数据帧格式

[编辑]

数据帧中的数据经常存储为两种格式：堆叠（stack）格式或记录（record）格式。在堆叠格式中，针对每个主题（subject）在适用情况下有多个横行，故而也称为“长”格式。在记录格式中，针对每个主题典型地有一个横行，故而也称为“宽”格式。在这个例子中，如果要对纵列`'place'`标识出的每个唯一的变量（`'A', 'B', 'C', 'D'`）进行时间序列运算，更好的表示形式为：诸纵列都对应唯一的变量，即对应不同的观测地点或观测者，而日期索引（`'date'`）标识出每个（不可细分的）个体观测。为此使用`pivot()`，将数据帧从堆叠格式重制形状为记录格式：

>>> df.drop([0, 4, 8]).pivot(index='date', columns='place')
value                 value1
place          A    B    C     D      A    B    C     D
date
2023-01-01   NaN  3.1  6.1   9.1    NaN  3.2  6.2   9.2
2023-01-02   1.1  NaN  7.1  10.1    1.2  NaN  7.2  10.2
2023-01-03   2.1  5.1  NaN  11.1    2.2  5.2  NaN  11.2
>>>

这里删除了三个横行展示了`NaN`被用来表示缺失数据。这里在`pivot()`的输入数据帧的诸纵列中，通过`index`参数指定了用作索引的纵列（`'date'`），通过`columns`参数指定了用作变量的纵列（`'place'`），但没有通过指定`values`参数于多个值纵列（`'value', 'value1'`）里选取其中之一，故而结果数据帧的诸纵列被纳入层级式索引（即多重索引`MultiIndex`），其最顶层指示出各自的值纵列，即依据观测量的不同而进行顶层分组。

### 串接运算

[编辑]

使用`concat()`对数据帧进行串接（英语：Set operations (SQL)）运算：

>>> df1 = df.drop(columns='value').rename(columns={'value1': 'value'})
>>> df1 = pd.concat([df.drop(columns='value1'), df1], ignore_index=True)
>>> df1.shape
(24, 3)
>>>
>>> data1 = [
...     ('A', pd.to_datetime('2023-01-01'), 0.3),
...     ('A', pd.to_datetime('2023-01-02'), 1.3)
... ]
>>>
>>> new_rows = pd.DataFrame(data1, columns=['place', 'date', 'value'])
>>> pd.concat([df1, new_rows], ignore_index=True).tail(3)
place       date  value
23     D 2023-01-03   11.2
24     A 2023-01-01    0.3
25     A 2023-01-02    1.3
>>>
>>> df_A = df1[df1['place']=='A'].drop(columns='place')
>>> df_A
date  value
0  2023-01-01    0.1
1  2023-01-02    1.1
2  2023-01-03    2.1
12 2023-01-01    0.2
13 2023-01-02    1.2
14 2023-01-03    2.2
>>>
>>> df_B = df1[df1['place']=='B'].drop(columns='place')
>>> df_C = df1[df1['place']=='C'].drop(columns='place')
>>> df_D = df1[df1['place']=='D'].drop(columns='place')
>>> df1 = pd.concat([df_A, df_B, df_C, df_D], keys=['A', 'B', 'C', 'D']) \
...     .droplevel(1).rename_axis('place').reset_index()
>>>

### 分组聚合运算

[编辑]

使用`groupby()`和紧随其后的`agg()`，对数据帧进行分组（英语：Group by (SQL)）并聚合（英语：Aggregate function）运算：

>>> df2 = df1.groupby(['date', 'place']).agg({'value': 'sum'})
>>> df2
value
date       place
2023-01-01 A        0.3
B        6.3
C       12.3
D       18.3
2023-01-02 A        2.3
B        8.3
C       14.3
D       20.3
2023-01-03 A        4.3
B       10.3
C       16.3
D       22.3
>>>
>>> df2.reorder_levels(['place', 'date']).sort_index()
value
place date
A     2023-01-01    0.3
2023-01-02    2.3
2023-01-03    4.3
B     2023-01-01    6.3
2023-01-02    8.3
2023-01-03   10.3
C     2023-01-01   12.3
2023-01-02   14.3
2023-01-03   16.3
D     2023-01-01   18.3
2023-01-02   20.3
2023-01-03   22.3
>>>
>>> df2.shape
(12, 1)
>>>
>>> df2.index
MultiIndex([('2023-01-01', 'A'),
('2023-01-01', 'B'),
('2023-01-01', 'C'),
('2023-01-01', 'D'),
('2023-01-02', 'A'),
('2023-01-02', 'B'),
('2023-01-02', 'C'),
('2023-01-02', 'D'),
('2023-01-03', 'A'),
('2023-01-03', 'B'),
('2023-01-03', 'C'),
('2023-01-03', 'D')],
names=['date', 'place'])
>>>
>>> df2.columns
Index(['value'], dtype='object')
>>>
>>> df2.loc[('2023-01-02', 'A')]
value    2.3
Name: (2023-01-02 00:00:00, A), dtype: float64
>>>
>>> df2.loc['2023-01-02']
value
place
A        2.3
B        8.3
C       14.3
D       20.3
>>>
>>> df2.xs('A', level='place')
value
date
2023-01-01    0.3
2023-01-02    2.3
2023-01-03    4.3
>>>

### 枢轴聚合运算

[编辑]

使用`pivot_table()`，对数据帧进行枢轴聚合运算：

>>> df3 = df1.pivot_table(index='date', columns='place', aggfunc='sum')
>>> df3
value
place          A     B     C     D
date
2023-01-01   0.3   6.3  12.3  18.3
2023-01-02   2.3   8.3  14.3  20.3
2023-01-03   4.3  10.3  16.3  22.3
>>>
>>> df3.shape
(3, 4)
>>>
>>> df3.to_numpy()
array([[ 0.3,  6.3, 12.3, 18.3],
[ 2.3,  8.3, 14.3, 20.3],
[ 4.3, 10.3, 16.3, 22.3]])
>>>
>>> df3.index
DatetimeIndex(['2023-01-01', '2023-01-02', '2023-01-03'], dtype='datetime64[ns]', name='date', freq=None)
>>>
>>> df3.columns
MultiIndex([('value', 'A'),
('value', 'B'),
('value', 'C'),
('value', 'D')],
names=[None, 'place'])
>>>
>>> df1.pivot_table(index='date', columns='place', values='value', aggfunc='sum').columns
Index(['A', 'B', 'C', 'D'], dtype='object', name='place')
>>>
>>> df3['value'].columns
Index(['A', 'B', 'C', 'D'], dtype='object', name='place')
>>>
>>> df3[('value', 'A')]
date
2023-01-01    0.3
2023-01-02    2.3
2023-01-03    4.3
Name: (value, A), dtype: float64
>>>
>>> df3.stack().shape
(12, 1)
>>> df2.unstack().shape
(3, 4)
>>>

### 归并运算

[编辑]

使用`merge()`，对数据帧进行归并运算：

>>> sr_A = df3[('value', 'A')]
>>> sr_B = df3[('value', 'B')]
>>> sr_C = df3[('value', 'C')]
>>> sr_D = df3[('value', 'D')]
>>> merge_date = lambda x, y: pd.merge(x, y, on='date')
>>> df3 = merge_date(merge_date(sr_A, sr_B), merge_date(sr_C, sr_D)) \
...     .rename_axis([None, 'place'], axis=1)
>>>
>>> pd.merge(df_A, df_B.drop('2023-01-02'), on='date')
value
A     B
date
2023-01-01   0.3   6.3
2023-01-03   4.3  10.3
>>>
>>> pd.merge(df_A, df_B.drop('2023-01-02'), on='date', how='left')
value
A     B
date
2023-01-01   0.3   6.3
2023-01-02   2.3   NaN
2023-01-03   4.3  10.3
>>>

### 绘图输出

[编辑]

例子代码生成的条形图。

用matplotlib为数据帧绘制条形图：

>>> df_axis0, df_axis1 = df3.shape
>>> df_columns = df3.to_dict(orient='list')
>>> df_index = df3.index.to_list()
>>> x = np.arange(df_axis0)
>>> width = 1/(df_axis1 + 1)
>>> mult = 0
>>>
>>> fig, ax = plt.subplots(layout='constrained')
>>> for name, value in df_columns.items():
...     offset = width * mult
...     rects = ax.bar(x + offset, value, width, label=name[1])
...     ax.bar_label(rects, padding=3)
...     mult += 1
...
[Text(0, 3, '0.3'), Text(0, 3, '2.3'), Text(0, 3, '4.3')]
[Text(0, 3, '6.3'), Text(0, 3, '8.3'), Text(0, 3, '10.3')]
[Text(0, 3, '12.3'), Text(0, 3, '14.3'), Text(0, 3, '16.3')]
[Text(0, 3, '18.3'), Text(0, 3, '20.3'), Text(0, 3, '22.3')]
>>> ax.set_xticks(x + width*(df_axis1 - 1)/2,
...     [x.strftime('%Y-%m-%d') for x in df_index])
[<matplotlib.axis.XTick object at 0x7bb6925408f0>, <matplotlib.axis.XTick object at 0x7bb692541700>, <matplotlib.axis.XTick object at 0x7bb6925421e0>]
>>> ax.legend()
<matplotlib.legend.Legend object at 0x7bb696123aa0>
>>> ax.grid(axis='y', linestyle=':')
>>> ax.set_axisbelow(True)
>>> plt.show()
>>>

### CSV文件操作

[编辑]

导出和导入CSV文件：

>>> df2.to_csv('dftest.csv', float_format='%.1f')
>>>
>>> df4 = pd.read_csv('dftest.csv', index_col=[0,1])
>>> df4.shape
(12, 1)

在不指定`header`参数即采用其缺省值之时，从导入文件标头即第一横行推导出数据的纵列名字。在导入文件时采用`index_col`参数，指定用作索引即横行标签的纵列。在标头的纵列数大于数据记录的纵列数之时，标头末位多出的纵列被设置为`NaN`；在标头的纵列数小于数据记录的纵列数之时，数据记录首位多出的纵列被用作索引；在标头的纵列数等于数据记录的纵列数，并且未指定索引列之时，则自动增加默认的没有名字的范围索引作为索引；在标头的纵列数等于数据记录的纵列数，并且已指定索引列之时，采用指定纵列作为索引。

在导入文件时可以通过`usecols`参数指定选用的纵列子集。如果所导入的文件没有标头，则需要指定`header=None`，还可以使用`names`参数，为导入数据指定纵列名字。如果所导入的文件有标头，并且要使用`names`参数指定替代它的纵列名字，则需要同时指定`header=0`。在导出文件时索引总是被导出的，可以使用`index_label`参数，为没有名字的索引纵列补充指定其名字。在导入pandas所导出的文件之时，需要指定索引列来避免再次自动增加缺省索引。

当数据帧是记录格式，故而`columns`方向采用了多重索引之时，所导出的CSV文件的标头有多个横行，以这里的数据帧`df3`为例，在导入它之时需要指定`header=[0, 1]`和`index_col=0`，但不能同时使用`usecols`或`names`参数：

>>> df3.to_csv('dftest.csv', float_format='%.1f')
>>>
>>> df4 = pd.read_csv('dftest.csv', header=[0, 1], index_col=0)
>>> df4.shape
(3, 4)

使用util-linux工具组成员`column`来查看导出的CSV文件：

$ cat dftest.csv | column -s, -o, -t
,value,value,value,value
place     ,A    ,B    ,C    ,D
date      ,     ,     ,     ,
2023-01-01,0.3  ,6.3  ,12.3 ,18.3
2023-01-02,2.3  ,8.3  ,14.3 ,20.3
2023-01-03,4.3  ,10.3 ,16.3 ,22.3

这里的前两横行的除了第一纵列之外的纵列，指定多层索引的纵列名字为`[('value', 'A'), ('value', 'B'), ('value', 'C'), ('value', 'D')]`。第一纵列的前两单元，指定了诸纵列`columns`的多重索引自身的名字列表为`[None, 'place']`，而第一纵列的第三单元，指定了索引`index`的日期时间索引自身的名字为`'date'`。

### JSON文件操作

[编辑]

导出和导入JSON文件：

>>> df3.to_json('dftest.json', orient='index', date_format='iso', date_unit='s')
>>>
>>> df4 = pd.read_json('dftest.json', orient='index')
>>> df4.shape
(3, 4)
>>>
>>> df4.columns
Index(['('value', 'A')', '('value', 'B')', '('value', 'C')', '('value', 'D')'], dtype='object')
>>>
>>> df4.columns = pd.MultiIndex.from_tuples([eval(x) for x in df4.columns])
>>> df4.columns.names = [None, 'place']
>>> df4.index.name = 'date'

这里指定了`orient`（方向）为`'index'`（索引），即采用横行为主（英语：Row- and column-major order）次序；这里指定了日期时间格式为ISO 8601标准格式，并且指定了时间单位为秒。JSON对象的键只能是字符串，在导出为JSON文件之时，元组被转换成字符串；而在导入它之时，需要通过`eval()`将其再转换为元组。

使用jq语言实现`jq`来查看导出的JSON文件：

$ cat dftest.json | jq

"2023-01-01T00:00:00": {
"('value', 'A')": 0.3,
"('value', 'B')": 6.3,
"('value', 'C')": 12.3,
"('value', 'D')": 18.3

"2023-01-02T00:00:00": {
"('value', 'A')": 2.3,
"('value', 'B')": 8.3,
"('value', 'C')": 14.3,
"('value', 'D')": 20.3

"2023-01-03T00:00:00": {
"('value', 'A')": 4.3,
"('value', 'B')": 10.3,
"('value', 'C')": 16.3,
"('value', 'D')": 22.3

在导出的数据中，不包含诸纵列`columns`的多重索引自身的名字列表即`[None, 'place']`，不包含索引`index`自身的名字即`'date'`。

### HDF5文件操作

[编辑]

导出和导入HDF5文件基于了PyTables[19]：

>>> df3.to_hdf('dftest.h5', key='df3', mode='w')
>>> df.to_hdf('dftest.h5', key='df', mode='a')
>>>
>>> df4 = pd.read_hdf('dftest.h5', key='df3')
>>> df4.shape
(3, 4)

这里通过键（`key`）参数，指定了与数据帧相对应的在HDF5文件中的群组（Group），对它采用了缺省的`'fixed'`（固定）存储格式。文件打开模态`'w'`是为“写”（write）即“新建”，而打开模态`'a'`是为“附加”（append）。

使用`hdf5-tools`工具组成员`h5ls`来查看导出的HDF5文件：

$ h5ls dftest.h5
df                       Group
df3                      Group
$ h5ls -r -d dftest.h5/df3
/axis0_label0            Dataset {4}
Data:
0, 0, 0, 0
/axis0_label1            Dataset {4}
Data:
0, 1, 2, 3
/axis0_level0            Dataset {1}
Data:
"value"
/axis0_level1            Dataset {4}
Data:
"A", "B", "C", "D"
/axis1                   Dataset {3}
Data:
1672531200000000000, 1672617600000000000, 1672704000000000000
/block0_items_label0     Dataset {4}
Data:
0, 0, 0, 0
/block0_items_label1     Dataset {4}
Data:
0, 1, 2, 3
/block0_items_level0     Dataset {1}
Data:
"value"
/block0_items_level1     Dataset {4}
Data:
"A", "B", "C", "D"
/block0_values           Dataset {3, 4}
Data:
0.3, 6.3, 12.3, 18.3, 2.3, 8.3, 14.3, 20.3, 4.3, 10.3, 16.3, 22.3

这里的HDF5文件中的日期时间表示，是以纳秒为单位的UNIX时间纪元（英语：Epoch (computing)）的时间戳。这种存储格式保存了数据帧的两个轴和所有的块[20]，它采用的轴编号`0`和`1`与编程API所用的NumPy轴编号相反[21]。这里的`df3`存储只有一个块，这个块的`items`的内容同于`axis0`。下面查看`df`存储的情况，它的四个纵列被整合（`consolidate`）为三个块，其`items`的并集同于`axis0`:

$ h5ls -r dftest.h5/df
/axis0                   Dataset {4}
/axis1                   Dataset {12}
/block0_items            Dataset {1}
/block0_values           Dataset {12, 1}
/block1_items            Dataset {2}
/block1_values           Dataset {12, 2}
/block2_items            Dataset {1}
/block2_values           Dataset {1/Inf}

保存HDF5文件还可采用`'table'`（表格）格式，HDF5文件中这种存储格式的群组，可以直接在其上进行查询和过滤：

>>> df3.to_hdf('dftest.h5', key='df3t', format='table', mode='a')
>>>
>>> pd.read_hdf('dftest.h5', key='df3t', where='index > 20230101', columns=[('value', 'A'), ('value', 'C')])
value
place          A     C
date
2023-01-02   2.3  14.3
2023-01-03   4.3  16.3

查看HDF5文件中的这种存储格式：

$ h5ls dftest.h5/df3t
_i_table                 Group
table                    Dataset {3/Inf}
$ h5ls -r -d dftest.h5/df3t/table
df4/table                Dataset {3/Inf}
Data:
{1672531200000000000, [0.3,6.3,12.3,18.3]},
{1672617600000000000, [2.3,8.3,14.3,20.3]},
{1672704000000000000, [4.3,10.3,16.3,22.3]}

这里的`_i_table/index`群组存储了PyTables的`tables.index`模块所存取的诸多内容[22]。

### netCDF文件操作

[编辑]

导出和导入netCDF文件可以借助`xarray`，它依赖于pandas，它通过netcdf4-python支持导入导出netCDF-4格式数据[23]，通过SciPy支持其他版本netCDF格式。`xarray`能够在自身的数据阵列（`DataArray`）与pandas的序列之间，在自身的数据集（`Dataset`）与pandas的数据帧之间，进行相互转换[24]：

>>> import xarray as xr
>>>
>>> df2.to_xarray()
<xarray.Dataset> Size: 152B
Dimensions:  (date: 3, place: 4)
Coordinates:
* date     (date) datetime64[ns] 24B 2023-01-01 2023-01-02 2023-01-03
* place    (place) object 32B 'A' 'B' 'C' 'D'
Data variables:
value    (date, place) float64 96B 0.3 6.3 12.3 18.3 ... 4.3 10.3 16.3 22.3
>>>
>>> df3.to_xarray()
<xarray.Dataset> Size: 120B
Dimensions:         (date: 3)
Coordinates:
* date            (date) datetime64[ns] 24B 2023-01-01 2023-01-02 2023-01-03
Data variables:
('value', 'A')  (date) float64 24B 0.3 2.3 4.3
('value', 'B')  (date) float64 24B 6.3 8.3 10.3
('value', 'C')  (date) float64 24B 12.3 14.3 16.3
('value', 'D')  (date) float64 24B 18.3 20.3 22.3
>>>
>>> df2.to_xarray().to_netcdf('dftest.nc')
>>>
>>> df4 = xr.open_dataset('dftest.nc').to_dataframe()
>>> df4.shape
(12, 1)

这里的从堆叠格式的数据帧`df2`转换出来的数据集可以导出至netCDF文件，而从记录格式的数据帧`df3`转换出来的数据集因变量名字而不能直接导出至netCDF文件。

使用`netcdf-bin`工具组成员`ncdump`来查看导出的netCDF文件：

$ ncdump dftest.nc
netcdf dftest {
dimensions:
date = 3 ;
place = 4 ;
variables:
double value(date, place) ;
value:_FillValue = NaN ;
int64 date(date) ;
date:units = "days since 2023-01-01 00:00:00" ;
date:calendar = "proleptic_gregorian" ;
string place(place) ;
data:

value =
0.3, 6.3, 12.3, 18.3,
2.3, 8.3, 14.3, 20.3,
4.3, 10.3, 16.3, 22.3 ;

date = 0, 1, 2 ;

place = "A", "B", "C", "D" ;

$ ncdump -k dftest.nc
netCDF-4
$ h5ls -r -d dftest.nc
/                        Group
/date                    Dataset {3}
Data:
0, 1, 2
/place                   Dataset {4}
Data:
"A", "B", "C", "D"
/value                   Dataset {3, 4}
Data:
0.3, 6.3, 12.3, 18.3, 2.3, 8.3, 14.3, 20.3, 4.3, 10.3, 16.3, 22.3

这里的日期时间表示遵循了气候和预报元数据约定（英语：Climate and Forecast Metadata Conventions）[25]，采用的时间单位为距离某个指定的开始日期时间的日数，历法为前推格里高利历。`ncdump`的输出所称谓的变量，代表相同类型的值的多维阵列。这里有三个变量：`value`是数据变量，`date`和`place`是坐标变量。变量声明指定了变量的数据类型、名字和以维度名字列表描述的形状，例如`double value(date, place)`，维度名字可以是`x, y, z, t`等等，而这里的维度名字同于对应的坐标变量名字。

### SQL关系数据库操作

[编辑]

下面通过SQLAlchemy将数据帧导出和导入于SQL关系数据库SQLite：

>>> from sqlalchemy import create_engine
>>> engine = create_engine("sqlite:///dftest.db")
>>>
>>> df2.to_sql(name='df2', con=engine)

>>>
>>> with engine.connect() as conn:
...     df4 = pd.read_sql('SELECT * FROM df2', conn)
...
>>>
>>> df4.shape
(12, 3)
>>> df4['date'] = pd.to_datetime(df4['date'])
>>> df4 = df4.set_index(['date', 'place'])
>>> df4.shape
(12, 1)

使用SQLite的命令行界面来查看导出的数据库文件：

$ echo '.tables' | sqlite3 dftest.db
df2
$ echo '.schema df2' | sqlite3 dftest.db
CREATE TABLE df2 (
date DATETIME,
place TEXT,
value FLOAT

CREATE INDEX ix_df2_date ON df2 (date);
CREATE INDEX ix_df2_place ON df2 (place);
$ echo 'SELECT * FROM df2' | sqlite3 dftest.db
2023-01-01 00:00:00.000000|A|0.3
2023-01-01 00:00:00.000000|B|6.3
2023-01-01 00:00:00.000000|C|12.3
2023-01-01 00:00:00.000000|D|18.3
2023-01-02 00:00:00.000000|A|2.3
2023-01-02 00:00:00.000000|B|8.3
2023-01-02 00:00:00.000000|C|14.3
2023-01-02 00:00:00.000000|D|20.3
2023-01-03 00:00:00.000000|A|4.3
2023-01-03 00:00:00.000000|B|10.3
2023-01-03 00:00:00.000000|C|16.3
2023-01-03 00:00:00.000000|D|22.3

SQLite将SQL的数据类型`DATETIME`硬性指定为亲和`NUMERIC`，而`NUMERIC`可以按其适合情况转换为五个存储类别（`NULL`、`INTEGER`、`REAL`、`TEXT`或`BLOB`）之一，这里的数据帧`df2`的`date`纵列中的数据，被转换成为`INTEGER`、`REAL`和`TEXT`三者中的`TEXT`即文本字符串。

## 参见

[编辑]

* NumPy
* R语言
* Scikit-learn
* statsmodels（英语：statsmodels）
* 数值分析软件

## 引用

[编辑]

1. ^ 1.0 1.1 Release 2.3.1. 2025年7月7日  [2025年7月17日].
2. ^ License – Package overview – pandas 1.0.0 documentation. pandas. 28 January 2020  [30 January 2020]. （原始内容存档于2012-02-14）.
3. ^ Wes McKinney. pandas: a Foundational Python Library for Data Analysis and Statistics (PDF). 2011  [2 August 2018]. （原始内容存档 (PDF)于2015-05-13）. "The library’s name derives from panel data, a common term for multidimensional data sets encountered in statistics and econometrics."
4. ^ McKinney, Wes. Python for Data Analysis, Second Edition. O'Reilly Media. 2017: 13. ISBN 9781491957660.
5. ^ About pandas — History of development — Timeline.  [2023-09-30]. （原始内容存档于2023-10-10）.
6. ^ Python for Data Analysis, 3E.  [2023-10-06]. （原始内容存档于2023-11-07）.
7. ^ DataFrame.  [2022-09-01]. （原始内容存档于2022-09-01）.
8. ^ Indexing and selecting data.  [2020-09-12]. （原始内容存档于2020-09-15）.
9. ^ Merge, join, concatenate and compare.  [2020-09-12]. （原始内容存档于2020-09-15）.
10. ^ Reshaping and pivot tables.  [2020-09-12]. （原始内容存档于2020-09-15）.
11. ^ Essential basic functionality — Matching / broadcasting behavior.  [2023-12-22]. （原始内容存档于2024-04-21）.
12. ^ Intro to data structures — Data alignment and arithmetic.  [2023-12-22]. （原始内容存档于2022-09-01）.
13. ^ Working with missing data.  [2023-12-22]. （原始内容存档于2024-05-16）.
14. ^ IO tools (text, CSV, HDF5, …).  [2020-09-12]. （原始内容存档于2020-09-15）.
15. ^ McKinney, Wes. Apache Arrow and the "10 Things I Hate About pandas". wesmckinney.com. 21 September 2017  [21 December 2023]. （原始内容存档于2024-05-25） （英语）.
16. ^ Python tools for data visualization — High-level tools.  [2023-09-28]. （原始内容存档于2023-09-28）.
17. ^ Pandas Plotting Backend in Python.  [2024-09-24]. （原始内容存档于2025-01-28）.
18. ^ DuckDB Guides — SQL on Pandas.  [2023-09-29]. （原始内容存档于2023-10-03）.
19. ^ PyTables: hierarchical datasets in Python.  [2023-09-28]. （原始内容存档于2023-08-24）.
20. ^ Internal Structure of Pandas DataFrames.  [2023-12-25]. （原始内容存档于2023-12-25）.
21. ^ NumPy glossary.
22. ^ Source code for tables.index.  [2023-12-25]. （原始内容存档于2023-12-25）.
23. ^ netcdf4-python: Python/numpy interface to the netCDF C library.  [2023-10-07]. （原始内容存档于2023-10-12）.
24. ^ xarray User Guide － Working with pandas.  [2022-09-04]. （原始内容存档于2022-09-04）.
25. ^ NetCDF Climate and Forecast (CF) Metadata Conventions — Time Coordinate.  [2023-10-09]. （原始内容存档于2023-10-12）.
xarray User Guide — Weather and climate data.  [2023-10-09]. （原始内容存档于2023-10-12）.

## 延伸阅读

[编辑]

* McKinney, Wes. Python for Data Analysis: Data Wrangling with pandas, NumPy, and Jupyter 3rd Edition. O'Reilly. 2022  [2023-10-06]. ISBN 978-1-0981-0403-0. （原始内容存档于2023-10-07）. 引文格式1维护：冗余文本 (link)
* Chen, Daniel Y. Pandas for Everyone : Python Data Analysis 2nd Edition. Addison-Wesley. 2022  [2023-10-06]. ISBN 978-0-1378-9105-4. （原始内容存档于2023-10-07）. 引文格式1维护：冗余文本 (link)
* Molin, Stefanie. Hands-On Data Analysis with Pandas: Efficiently perform data collection, wrangling, analysis, and visualization using Python. Packt. 2019  [2023-10-06]. ISBN 978-1-7896-1532-6. （原始内容存档于2023-10-07）.
* VanderPlas, Jake. Python Data Science Handbook: Essential Tools for Working with Data. O'Reilly. 2016  [2023-10-06]. ISBN 978-1-4919-1205-8. （原始内容存档于2023-10-08）.

## 外部链接

[编辑]

* Pathak, Chankey. Pandas Cookbook. 2018  [2023-10-06]. （原始内容存档于2023-10-07）.

* 查
* 论
* 编

Python科学软件

* NumPy
* SciPy
* matplotlib
* pandas
* scikit-learn
* scikit-image（英语：scikit-image）
* statsmodels（英语：statsmodels）
* MayaVi（英语：MayaVi）
* 更多

*[查]: 查看该模板
*[论]: 讨论该模板
*[编]: 编辑该模板