IO Tools (Text, CSV, HDF5, ...)¶
pandas I / O API是一组顶级的reader
函数,像pd.read_csv()
访问,通常返回一个pandas
对象。
对应的writer
函数是对象方法,像df.to_csv()
Here是其中一些IO方法的非正式性能比较。
注意
For examples that use the StringIO
class, make sure you import it according to your Python version, i.e. from StringIO import StringIO
for Python 2 and from io import StringIO
for Python 3.
CSV & Text files¶
用于读取文本文件的两个主力功能(a.k.a.平面文件)为read_csv()
和read_table()
。他们都使用相同的解析代码智能地将表格数据转换为DataFrame对象。有关某些高级策略,请参阅cookbook。
Parsing options¶
Basic¶
- filepath_or_buffer : 各种
- 要么是文件的路径(
str
,pathlib.Path
或py._path.local.LocalPath
),URL(包括http, ftp和S3位置),或任何具有read()
方法(例如打开的文件或StringIO
)的对象。 - sep : str, defaults to
- 分隔符使用。如果sep为
None
,将尝试自动确定这一点。长度大于1个字符且与'\s+'
不同的分隔符将被解释为正则表达式,将强制使用Python解析引擎,并忽略数据中的引号。正则表达式示例:'\\r\\t'
。 - 分隔符 : str,默认
- sep的备用参数名称。
- delim_whitespace : boolean,default False
指定是否使用空格(例如
' '
或'\t'
)作为分隔符。相当于设置sep='\s+'
。如果此选项设置为True,则不应为delimiter
参数传入任何内容。版本0.18.1中的新功能:支持Python解析器。
','
for read_csv()
, \t
for read_table()
None
Column and Index Locations and Names¶
- 标题 : int或ints列表,默认
- 要用作列名称的行号,以及数据的开始。如果没有传递
names
,默认行为就像header=0
,否则就像header=None
。显式传递header=0
,以便能够替换现有名称。头部可以是指定列的多索引的行位置的整数列表,例如[0,1,3]
。未指定的插入行将被跳过(例如,在此示例中跳过2)。请注意,如果skip_blank_lines=True
,此参数将忽略已注释的行和空行,因此header = 0表示数据的第一行,而不是文件的第一行。 - 名称 : 数组样,默认
- 要使用的列名称列表。如果文件不包含标题行,则应明确传递
header=None
。除非mangle_dupe_cols=True
,此列表中的重复项是不允许的,这是默认值。 - index_col : int或序列或
- 用作DataFrame的行标签的列。如果给出序列,则使用MultiIndex。如果您在每行末尾都有带分隔符的格式不正确的文件,则可以考虑
index_col=False
强制将pandas强制为而不是使用第一列作为索引)。 - usecols : 数组样,默认
- 返回列的子集。此数组中的所有元素必须是位置(即,文档列中的整数索引)或对应于用户在名称中提供或从文档标题行推断的列名称的字符串。例如,有效的usecols参数将是[0,1,2]或['foo','bar','baz']。使用此参数会导致更快的解析时间和更低的内存使用率。
- as_recarray : boolean,默认
DEPRECATED:此参数将在以后的版本中删除。请改用
pd.read_csv(...).to_records()
。在解析数据后,返回NumPy recarray而不是DataFrame。如果设置为
True
,则此选项优先于squeeze
参数。此外,由于行索引在此类格式中不可用,因此将忽略index_col
参数。- 挤 : boolean,默认
- 如果解析的数据只包含一列,则返回一个Series。
- 字首 : str,默认
- 在没有标题时添加到列号的前缀,例如'X'代表X0,X1,...
- mangle_dupe_cols : 布尔值,默认
- 重复的列将被指定为“X.0”...“X.N”,而不是“X”...“X”。如果在列中存在重复的名称,则传入False将导致覆盖数据。
'infer'
None
False
,默认None
None
False
False
None
True
General Parsing Configuration¶
- dtype : 输入列的名称或字典 - >类型,默认
- 数据或列的数据类型。例如。
{'a': np.float64, 'b': np.int32} t0>(不支持
使用str或对象来保留而不是解释dtype。engine='python'
)。 - 驱动 : {
- 解析器引擎使用。C引擎速度更快,而python引擎目前更加完善。
- 转换器 : dict,默认
- 说明转换某些列中的值的函数。键可以是整数或列标签。
- true_values : 列表,默认
- 要考虑的值为
True
。 - false_values : 列表,默认
- 要考虑的值为
False
。 - skipinitialspace : boolean,默认
- 跳过分隔符后的空格。
- skiprows : 列表状或整数,默认
- 要跳过的行号(0索引)或要跳过的行数(int)在文件的开头。
- skipfooter : int,默认
- 要跳过的文件底部的行数(不支持engine ='c')。
- skip_footer : int,默认
- DEPRECATED:使用
skipfooter
参数,因为它们是相同的 - nrows : int,默认
- 要读取的文件的行数。适用于读取大文件的片段。
- 内存不足 : 布尔值,默认
- 在内部以块的方式处理文件,导致解析时内存使用较少,但可能是混合类型推断。要确保没有混合类型,请设置
False
,或使用dtype
参数指定类型。请注意,无论如何,整个文件都读入单个DataFrame,请使用chunksize
或iterator
参数以块形式返回数据。(只有C解析器有效) - buffer_lines : int,默认无
- DEPRECATED:此参数将在未来版本中删除,因为其值不受解析器的影响
- compact_ints : boolean,default False
DEPRECATED:此参数将在以后的版本中删除
如果
compact_ints
是True
,则对于任何整数为dtype的列,解析器将尝试将其作为最小整数dtype
根据use_unsigned
参数的规范,可以是有符号或无符号。- use_unsigned : boolean,default False
DEPRECATED:此参数将在以后的版本中删除
如果整数列被压缩(即
compact_ints=True
),请指定该列是否应压缩到最小有符号或无符号整数dtype。- memory_map : boolean,default False
- 如果为
filepath_or_buffer
提供了文件路径,则将文件对象直接映射到内存上,并从中直接访问数据。使用此选项可以提高性能,因为不再有任何I / O开销。
None
'c'
,'python'
}None
None
None
False
None
0
0
None
True
NA and Missing Data Handling¶
- na_values : 标量,str,列表式或dict,默认
- 可识别为NA / NaN的其他字符串。如果dict通过,特定的每列NA值。By default the following values are interpreted as NaN:
'-1.#IND', '1.#QNAN', '1.#IND', '-1.#QNAN', '#N/A N/A', '#N/A', 'N/A', 'NA', '#NA', 'NULL', 'NaN', '-NaN', 'nan', '-nan', ''
. - keep_default_na : 布尔值,默认
- 如果指定了na_values且keep_default_na为
False
,则将覆盖默认NaN值,否则将追加到。 - na_filter : 布尔值,默认
- 检测缺失值标记(空字符串和na_values的值)。在没有任何NA的数据中,传递
na_filter=False
可以提高读取大文件的性能。 - 详细 : boolean,默认
- 指示放置在非数字列中的NA值的数量。
- skip_blank_lines : 布尔值,默认
- 如果
True
,则跳过空白行,而不是解释为NaN值。
None
True
True
False
True
Datetime Handling¶
- parse_dates : 布尔值或整数或名称列表或列表或dict列表,默认
- 如果
True
- >尝试解析索引。 - 如果
[1, 2, 3]
- >尝试将列1,2,3分别解析为单独的日期列。 - 如果
[[1, 3]]
- >合并列1和3并解析为单个日期列。 - 如果
{'foo' : [1, 3]} 列1,3作为日期和调用结果'foo'。
iso8601格式的日期存在快速路径。
- 如果
- infer_datetime_format : boolean,默认
- If
True
and parse_dates is enabled for a column, attempt to infer the datetime format to speed up the processing. - keep_date_col : boolean,默认
- 如果
True
和parse_dates指定合并多个列,则保留原始列。 - date_parser : 功能,默认
- 用于将字符串列序列转换为datetime实例数组的函数。默认使用
dateutil.parser.parser
进行转换。Pandas将尝试以三种不同的方式调用date_parser,如果发生异常,则推进到下一个:1)将一个或多个数组(由parse_dates定义)作为参数传递; 2)将由parse_dates定义的列中的字符串值连接(逐行)到单个数组中,并传递;和3)对于每一行,使用一个或多个字符串(对应于由parse_dates定义的列)作为参数调用date_parser一次。 - 日间 : boolean,默认
- DD / MM格式日期,国际和欧洲格式。
False
。False
False
None
False
Iteration¶
- 迭代器 : boolean,默认
- 返回TextFileReader对象以进行迭代或使用
get_chunk()
获取块。 - chunksize : int,默认
- 返回TextFileReader对象以进行迭代。请参阅下面的iterating and chunking。
False
None
Quoting, Compression, and File Format¶
- 压缩 : {
用于磁盘上数据的即时解压缩。如果'infer',则使用gzip,bz2,zip或xz,如果filepath_or_buffer是分别以'.gz','.bz2','.zip'或'.xz'结尾的字符串,否则不进行解压缩。如果使用'zip',ZIP文件必须只包含一个要读入的数据文件。设置为
None
,表示无解压缩。新版本0.18.1:支持'zip'和'xz'压缩。
- 数千 : str,默认
- 千位分隔符。
- 十进制 : str,default
- 识别为小数点的字符。例如。对欧洲数据使用
','
。 - float_precision : 字符串,默认为无
- 指定C引擎应该为浮点值使用哪个转换器。对于普通转换器,选项为
None
,对于高精度转换器,选项为high
,对于往返转换器选项为round_trip
。 - 线性判定器 : str(长度1),默认
- 将文件拆分成行的字符。只有C解析器有效。
- 匹配 : str(length 1)
- 用于表示带引号项目的开始和结束的字符。引号项可以包含分隔符,它将被忽略。
- 引用 : int或
- 每个
csv.QUOTE_*
常量的控制字段引用行为。使用QUOTE_MINIMAL
(0),QUOTE_ALL
(1),QUOTE_NONNUMERIC
(2)或QUOTE_NONE
。 - 双引号 : 布尔值,默认
- When
quotechar
is specified andquoting
is notQUOTE_NONE
, indicate whether or not to interpret two consecutivequotechar
elements inside a field as a singlequotechar
element. - escapechar : str(长度1),默认
- 引号时用于转义分隔符的单字符字符串为
QUOTE_NONE
。 - 评论 : str,默认
- 表示不应解析行的剩余部分。如果在行的开头找到,则该行将完全被忽略。此参数必须为单个字符。与空行一样(只要
skip_blank_lines=True
),完全注释的行就会被参数头忽略,而不会被skiprows忽略。例如,如果comment='#'
,用header = 0解析'#empty \ na,b,c \ n1,2,3' ,b,c'被当作报头。 - 编码 : str,默认
- 在读/写时用于UTF的编码(例如
'utf-8'
)。Python标准编码列表。 - 方言 : str或
- 如果
None
默认为Excel方言。如果sep长于1个字符,则忽略。有关详细信息,请参阅csv.Dialect
文档。 - tupleize_cols : boolean,默认
- 将列上的元组列表保留为原样(默认是将列转换为MultiIndex)。
'infer'
, 'gzip'
, 'bz2'
, 'zip'
, 'xz'
, None
}, default 'infer'
None
'.'
None
csv.QUOTE_*
实例,默认0
True
None
None
None
csv.Dialect
实例,默认None
False
Error Handling¶
- error_bad_lines : 布尔值,默认
- 默认情况下,具有太多字段的行(例如,具有太多逗号的csv行)将引发异常,并且不会返回DataFrame。如果
False
,那么这些“坏行”将从返回的DataFrame中删除(仅对C解析器有效)。请参阅下面的bad lines。 - warn_bad_lines : 布尔值,默认
- 如果error_bad_lines为
False
,而warn_bad_lines为True
,则会输出每个“坏行”的警告(仅对C解析器有效)。
True
True
考虑一个典型的CSV文件,在这种情况下,包含一些时间序列数据:
In [1]: print(open('foo.csv').read())
date,A,B,C
20090101,a,1,2
20090102,b,3,4
20090103,c,4,5
read_csv的默认值是创建具有简单编号行的DataFrame:
In [2]: pd.read_csv('foo.csv')
Out[2]:
date A B C
0 20090101 a 1 2
1 20090102 b 3 4
2 20090103 c 4 5
在索引数据的情况下,您可以传递要用作索引的列号或列名:
In [3]: pd.read_csv('foo.csv', index_col=0)
Out[3]:
A B C
date
20090101 a 1 2
20090102 b 3 4
20090103 c 4 5
In [4]: pd.read_csv('foo.csv', index_col='date')
Out[4]:
A B C
date
20090101 a 1 2
20090102 b 3 4
20090103 c 4 5
您还可以使用列列表创建层次索引:
In [5]: pd.read_csv('foo.csv', index_col=[0, 'A'])
Out[5]:
B C
date A
20090101 a 1 2
20090102 b 3 4
20090103 c 4 5
dialect
关键字在指定文件格式时具有更大的灵活性。默认情况下,它使用Excel方言,但您可以指定方言名称或csv.Dialect
实例。
假设您有未封闭的引号的数据:
In [6]: print(data)
label1,label2,label3
index1,"a,c,e
index2,b,d,f
默认情况下,read_csv
使用Excel方言,并将双引号作为引号字符,这会导致它在找到换行符之前找到换行符时失败。
我们可以使用dialect
解决这个问题
In [7]: dia = csv.excel()
In [8]: dia.quoting = csv.QUOTE_NONE
In [9]: pd.read_csv(StringIO(data), dialect=dia)
Out[9]:
label1 label2 label3
index1 "a c e
index2 b d f
所有的方言选项可以通过关键字参数单独指定:
In [10]: data = 'a,b,c~1,2,3~4,5,6'
In [11]: pd.read_csv(StringIO(data), lineterminator='~')
Out[11]:
a b c
0 1 2 3
1 4 5 6
另一个常用的方言选项是skipinitialspace
,跳过分隔符后的任何空格:
In [12]: data = 'a, b, c\n1, 2, 3\n4, 5, 6'
In [13]: print(data)
a, b, c
1, 2, 3
4, 5, 6
In [14]: pd.read_csv(StringIO(data), skipinitialspace=True)
Out[14]:
a b c
0 1 2 3
1 4 5 6
解析器每一次尝试“做正确的事情”,而不是非常脆弱。类型推理是一个相当大的交易。因此,如果列可以强制转换为整数dtype,而不改变内容,它将这样做。任何非数字列将通过作为对象dtype与其余的pandas对象。
Specifying column data types¶
从v0.10开始,可以指定整个DataFrame或单独列的数据类型:
In [15]: data = 'a,b,c\n1,2,3\n4,5,6\n7,8,9'
In [16]: print(data)
a,b,c
1,2,3
4,5,6
7,8,9
In [17]: df = pd.read_csv(StringIO(data), dtype=object)
In [18]: df
Out[18]:
a b c
0 1 2 3
1 4 5 6
2 7 8 9
In [19]: df['a'][0]
Out[19]: '1'
In [20]: df = pd.read_csv(StringIO(data), dtype={'b': object, 'c': np.float64})
In [21]: df.dtypes
Out[21]:
a int64
b object
c float64
dtype: object
幸运的是,pandas
提供了多种方法来确保您的列只包含一个dtype
。If you’re unfamiliar with these concepts, you can see here to learn more about dtypes, and here to learn more about object
conversion in pandas
.
例如,您可以使用read_csv()
的converters
参数:
In [22]: data = "col_1\n1\n2\n'A'\n4.22"
In [23]: df = pd.read_csv(StringIO(data), converters={'col_1':str})
In [24]: df
Out[24]:
col_1
0 1
1 2
2 'A'
3 4.22
In [25]: df['col_1'].apply(type).value_counts()
Out[25]:
<type 'str'> 4
Name: col_1, dtype: int64
或者您可以使用to_numeric()
函数在读取数据后强制dtypes,
In [26]: df2 = pd.read_csv(StringIO(data))
In [27]: df2['col_1'] = pd.to_numeric(df2['col_1'], errors='coerce')
In [28]: df2
Out[28]:
col_1
0 1.00
1 2.00
2 NaN
3 4.22
In [29]: df2['col_1'].apply(type).value_counts()
Out[29]:
<type 'float'> 4
Name: col_1, dtype: int64
它会将所有有效的解析转换为浮点数,将无效的解析作为NaN
。
最终,如何处理在包含混合dtypes的列中读取取决于您的具体需求。在上面的情况下,如果你想NaN
输出数据异常,则to_numeric()
可能是你最好的选择。然而,如果你想要强制所有的数据,不管类型,然后使用read_csv()
的converters
参数肯定是值得尝试。
注意
dtype
选项目前仅受C引擎支持。使用engine
指定dtype
而不是“c”会引发ValueError
。
注意
在某些情况下,使用包含混合dtypes的列读取异常数据将导致不一致的数据集。如果你依靠pandas推断你的列的dtypes,解析引擎将去推断不同数据块的dtypes,而不是一次性的整个数据集。因此,你可以结束与混合dtypes的列。例如,
In [30]: df = pd.DataFrame({'col_1':range(500000) + ['a', 'b'] + range(500000)})
In [31]: df.to_csv('foo')
In [32]: mixed_df = pd.read_csv('foo')
In [33]: mixed_df['col_1'].apply(type).value_counts()
Out[33]:
<type 'int'> 737858
<type 'str'> 262144
Name: col_1, dtype: int64
In [34]: mixed_df['col_1'].dtype
Out[34]: dtype('O')
将导致mixed_df对于某些块的块包含int
dtype,对于其他块包含str
,由于来自数据的混合dty读入。重要的是要注意,整个列将标记object
的dtype
,用于具有混合dtypes的列。
Specifying Categorical dtype¶
版本0.19.0中的新功能。
Categorical
列可以直接通过指定dtype='category'
In [35]: data = 'col1,col2,col3\na,b,1\na,b,2\nc,d,3'
In [36]: pd.read_csv(StringIO(data))
Out[36]:
col1 col2 col3
0 a b 1
1 a b 2
2 c d 3
In [37]: pd.read_csv(StringIO(data)).dtypes
Out[37]:
col1 object
col2 object
col3 int64
dtype: object
In [38]: pd.read_csv(StringIO(data), dtype='category').dtypes
Out[38]:
col1 category
col2 category
col3 category
dtype: object
可以使用dict规范将各个列解析为Categorical
In [39]: pd.read_csv(StringIO(data), dtype={'col1': 'category'}).dtypes
Out[39]:
col1 category
col2 object
col3 int64
dtype: object
注意
结果类别将始终被解析为字符串(对象dtype)。如果类别是数字,则可以使用to_numeric()
函数或适当时使用另一个转换器(例如to_datetime()
)转换类别。
In [40]: df = pd.read_csv(StringIO(data), dtype='category')
In [41]: df.dtypes
Out[41]:
col1 category
col2 category
col3 category
dtype: object
In [42]: df['col3']
Out[42]:
0 1
1 2
2 3
Name: col3, dtype: category
Categories (3, object): [1, 2, 3]
In [43]: df['col3'].cat.categories = pd.to_numeric(df['col3'].cat.categories)
In [44]: df['col3']
Out[44]:
0 1
1 2
2 3
Name: col3, dtype: category
Categories (3, int64): [1, 2, 3]
Naming and Using Columns¶
Handling column names¶
文件可以有也可以没有标题行。pandas假设第一行应该用作列名:
In [45]: data = 'a,b,c\n1,2,3\n4,5,6\n7,8,9'
In [46]: print(data)
a,b,c
1,2,3
4,5,6
7,8,9
In [47]: pd.read_csv(StringIO(data))
Out[47]:
a b c
0 1 2 3
1 4 5 6
2 7 8 9
通过与header
结合指定names
参数,您可以指示要使用的其他名称以及是否丢弃标题行(如果有):
In [48]: print(data)
a,b,c
1,2,3
4,5,6
7,8,9
In [49]: pd.read_csv(StringIO(data), names=['foo', 'bar', 'baz'], header=0)
Out[49]:
foo bar baz
0 1 2 3
1 4 5 6
2 7 8 9
In [50]: pd.read_csv(StringIO(data), names=['foo', 'bar', 'baz'], header=None)
Out[50]:
foo bar baz
0 a b c
1 1 2 3
2 4 5 6
3 7 8 9
如果标题位于第一行以外的行,请将行号传递到header
。这将跳过前面的行:
In [51]: data = 'skip this skip it\na,b,c\n1,2,3\n4,5,6\n7,8,9'
In [52]: pd.read_csv(StringIO(data), header=1)
Out[52]:
a b c
0 1 2 3
1 4 5 6
2 7 8 9
Duplicate names parsing¶
如果文件或标题包含重复的名称,则pandas默认会对这些名称进行重复数据删除,以防止数据覆盖:
In [53]: data = 'a,b,a\n0,1,2\n3,4,5'
In [54]: pd.read_csv(StringIO(data))
Out[54]:
a b a.1
0 0 1 2
1 3 4 5
没有更多的重复数据,因为默认情况下,mangle_dupe_cols=True
会修改一系列重复的列'X'...'X'变成'X.0'...'X.N '。如果mangle_dupe_cols = False
,可能会出现重复的数据:
In [2]: data = 'a,b,a\n0,1,2\n3,4,5'
In [3]: pd.read_csv(StringIO(data), mangle_dupe_cols=False)
Out[3]:
a b a
0 2 1 2
1 5 4 5
为了防止用户在重复数据中遇到此问题,如果mangle_dupe_cols != True,则会引发
:ValueError
t5>
In [2]: data = 'a,b,a\n0,1,2\n3,4,5'
In [3]: pd.read_csv(StringIO(data), mangle_dupe_cols=False)
...
ValueError: Setting mangle_dupe_cols=False is not supported yet
Filtering columns (usecols
)¶
usecols
参数允许您使用列名称或位置数字选择文件中的任何列子集:
In [55]: data = 'a,b,c,d\n1,2,3,foo\n4,5,6,bar\n7,8,9,baz'
In [56]: pd.read_csv(StringIO(data))
Out[56]:
a b c d
0 1 2 3 foo
1 4 5 6 bar
2 7 8 9 baz
In [57]: pd.read_csv(StringIO(data), usecols=['b', 'd'])
Out[57]:
b d
0 2 foo
1 5 bar
2 8 baz
In [58]: pd.read_csv(StringIO(data), usecols=[0, 2, 3])
Out[58]:
a c d
0 1 3 foo
1 4 6 bar
2 7 9 baz
Comments and Empty Lines¶
Ignoring line comments and empty lines¶
如果指定comment
参数,则完全注释的行将被忽略。默认情况下,完全空白行也将被忽略。这两个都是版本0.15中引入的API更改。
In [59]: data = '\na,b,c\n \n# commented line\n1,2,3\n\n4,5,6'
In [60]: print(data)
a,b,c
1,2,3
4,5,6
# commented line
In [61]: pd.read_csv(StringIO(data), comment='#')
Out[61]:
a b c
0 1 2 3
1 4 5 6
如果skip_blank_lines=False
,则read_csv
将不会忽略空行:
In [62]: data = 'a,b,c\n\n1,2,3\n\n\n4,5,6'
In [63]: pd.read_csv(StringIO(data), skip_blank_lines=False)
Out[63]:
a b c
0 NaN NaN NaN
1 1.0 2.0 3.0
2 NaN NaN NaN
3 NaN NaN NaN
4 4.0 5.0 6.0
警告
忽略行的存在可能产生涉及行号的模糊性;参数header
使用行号(忽略注释/空行),而skiprows
使用行号(包括注释/空行):
In [64]: data = '#comment\na,b,c\nA,B,C\n1,2,3'
In [65]: pd.read_csv(StringIO(data), comment='#', header=1)
Out[65]:
A B C
0 1 2 3
In [66]: data = 'A,B,C\n#comment\na,b,c\n1,2,3'
In [67]: pd.read_csv(StringIO(data), comment='#', skiprows=2)
Out[67]:
a b c
0 1 2 3
如果指定header
和skiprows
,则header
将相对于skiprows
的结尾。例如:
In [68]: data = '# empty\n# second empty line\n# third empty' \
In [68]: 'line\nX,Y,Z\n1,2,3\nA,B,C\n1,2.,4.\n5.,NaN,10.0'
In [69]: print(data)
# empty
# second empty line
# third emptyline
X,Y,Z
1,2,3
A,B,C
1,2.,4.
5.,NaN,10.0
In [70]: pd.read_csv(StringIO(data), comment='#', skiprows=4, header=1)
Out[70]:
A B C
0 1.0 2.0 4.0
1 5.0 NaN 10.0
Comments¶
有时评论或元数据可能包含在文件中:
In [71]: print(open('tmp.csv').read())
ID,level,category
Patient1,123000,x # really unpleasant
Patient2,23000,y # wouldn't take his medicine
Patient3,1234018,z # awesome
默认情况下,解析器在输出中包括注释:
In [72]: df = pd.read_csv('tmp.csv')
In [73]: df
Out[73]:
ID level category
0 Patient1 123000 x # really unpleasant
1 Patient2 23000 y # wouldn't take his medicine
2 Patient3 1234018 z # awesome
我们可以使用comment
关键字取消注释:
In [74]: df = pd.read_csv('tmp.csv', comment='#')
In [75]: df
Out[75]:
ID level category
0 Patient1 123000 x
1 Patient2 23000 y
2 Patient3 1234018 z
Dealing with Unicode Data¶
对于编码的unicode数据,应使用encoding
参数,这将导致在结果中将字节字符串解码为unicode:
In [76]: data = b'word,length\nTr\xc3\xa4umen,7\nGr\xc3\xbc\xc3\x9fe,5'.decode('utf8').encode('latin-1')
In [77]: df = pd.read_csv(BytesIO(data), encoding='latin-1')
In [78]: df
Out[78]:
word length
0 Träumen 7
1 Grüße 5
In [79]: df['word'][1]
Out[79]: u'Gr\xfc\xdfe'
一些将所有字符编码为多个字节(如UTF-16)的格式将不会正确解析,而不指定编码。Python标准编码的完整列表
Index columns and trailing delimiters¶
如果一个文件还有一列数据而不是列名数,则第一列将被用作DataFrame的行名称:
In [80]: data = 'a,b,c\n4,apple,bat,5.7\n8,orange,cow,10'
In [81]: pd.read_csv(StringIO(data))
Out[81]:
a b c
4 apple bat 5.7
8 orange cow 10.0
In [82]: data = 'index,a,b,c\n4,apple,bat,5.7\n8,orange,cow,10'
In [83]: pd.read_csv(StringIO(data), index_col=0)
Out[83]:
a b c
index
4 apple bat 5.7
8 orange cow 10.0
通常,您可以使用index_col
选项来实现此行为。
当在每个数据行的末尾使用定界符准备文件时,会出现一些异常情况,从而导致解析器混乱。要显式禁用索引列推断并放弃最后一列,请传递index_col=False
:
In [84]: data = 'a,b,c\n4,apple,bat,\n8,orange,cow,'
In [85]: print(data)
a,b,c
4,apple,bat,
8,orange,cow,
In [86]: pd.read_csv(StringIO(data))
Out[86]:
a b c
4 apple bat NaN
8 orange cow NaN
In [87]: pd.read_csv(StringIO(data), index_col=False)
Out[87]:
a b c
0 4 apple bat
1 8 orange cow
Date Handling¶
Specifying Date Columns¶
为了更好地使用datetime数据,read_csv()
和read_table()
使用关键字参数parse_dates
和date_parser
以允许用户指定各种列和日期/时间格式将输入文本数据转换为datetime
对象。
最简单的情况是传入parse_dates=True
:
# Use a column as an index, and parse it as dates.
In [88]: df = pd.read_csv('foo.csv', index_col=0, parse_dates=True)
In [89]: df
Out[89]:
A B C
date
2009-01-01 a 1 2
2009-01-02 b 3 4
2009-01-03 c 4 5
# These are python datetime objects
In [90]: df.index
Out[90]: DatetimeIndex(['2009-01-01', '2009-01-02', '2009-01-03'], dtype='datetime64[ns]', name=u'date', freq=None)
通常情况下,我们可能要分开存储日期和时间数据,或单独存储各种日期字段。parse_dates
关键字可用于指定解析日期和/或时间的列的组合。
您可以将列列表指定为parse_dates
,生成的日期列将预置到输出(以不影响现有列顺序),新的列名称将是组件列名称:
In [91]: print(open('tmp.csv').read())
KORD,19990127, 19:00:00, 18:56:00, 0.8100
KORD,19990127, 20:00:00, 19:56:00, 0.0100
KORD,19990127, 21:00:00, 20:56:00, -0.5900
KORD,19990127, 21:00:00, 21:18:00, -0.9900
KORD,19990127, 22:00:00, 21:56:00, -0.5900
KORD,19990127, 23:00:00, 22:56:00, -0.5900
In [92]: df = pd.read_csv('tmp.csv', header=None, parse_dates=[[1, 2], [1, 3]])
In [93]: df
Out[93]:
1_2 1_3 0 4
0 1999-01-27 19:00:00 1999-01-27 18:56:00 KORD 0.81
1 1999-01-27 20:00:00 1999-01-27 19:56:00 KORD 0.01
2 1999-01-27 21:00:00 1999-01-27 20:56:00 KORD -0.59
3 1999-01-27 21:00:00 1999-01-27 21:18:00 KORD -0.99
4 1999-01-27 22:00:00 1999-01-27 21:56:00 KORD -0.59
5 1999-01-27 23:00:00 1999-01-27 22:56:00 KORD -0.59
默认情况下,解析器会删除组件日期列,但您可以选择通过keep_date_col
关键字保留它们:
In [94]: df = pd.read_csv('tmp.csv', header=None, parse_dates=[[1, 2], [1, 3]],
....: keep_date_col=True)
....:
In [95]: df
Out[95]:
1_2 1_3 0 1 2 \
0 1999-01-27 19:00:00 1999-01-27 18:56:00 KORD 19990127 19:00:00
1 1999-01-27 20:00:00 1999-01-27 19:56:00 KORD 19990127 20:00:00
2 1999-01-27 21:00:00 1999-01-27 20:56:00 KORD 19990127 21:00:00
3 1999-01-27 21:00:00 1999-01-27 21:18:00 KORD 19990127 21:00:00
4 1999-01-27 22:00:00 1999-01-27 21:56:00 KORD 19990127 22:00:00
5 1999-01-27 23:00:00 1999-01-27 22:56:00 KORD 19990127 23:00:00
3 4
0 18:56:00 0.81
1 19:56:00 0.01
2 20:56:00 -0.59
3 21:18:00 -0.99
4 21:56:00 -0.59
5 22:56:00 -0.59
请注意,如果您希望将多个列合并到单个日期列中,则必须使用嵌套列表。In other words, parse_dates=[1, 2]
indicates that the second and third columns should each be parsed as separate date columns while parse_dates=[[1, 2]]
means the two columns should be parsed into a single column.
您还可以使用dict指定自定义名称列:
In [96]: date_spec = {'nominal': [1, 2], 'actual': [1, 3]}
In [97]: df = pd.read_csv('tmp.csv', header=None, parse_dates=date_spec)
In [98]: df
Out[98]:
nominal actual 0 4
0 1999-01-27 19:00:00 1999-01-27 18:56:00 KORD 0.81
1 1999-01-27 20:00:00 1999-01-27 19:56:00 KORD 0.01
2 1999-01-27 21:00:00 1999-01-27 20:56:00 KORD -0.59
3 1999-01-27 21:00:00 1999-01-27 21:18:00 KORD -0.99
4 1999-01-27 22:00:00 1999-01-27 21:56:00 KORD -0.59
5 1999-01-27 23:00:00 1999-01-27 22:56:00 KORD -0.59
重要的是要记住,如果要将多个文本列解析为单个日期列,则会在数据前面添加一个新列。index_col规范基于此新的列集合,而不是原始数据列:
In [99]: date_spec = {'nominal': [1, 2], 'actual': [1, 3]}
In [100]: df = pd.read_csv('tmp.csv', header=None, parse_dates=date_spec,
.....: index_col=0) #index is the nominal column
.....:
In [101]: df
Out[101]:
actual 0 4
nominal
1999-01-27 19:00:00 1999-01-27 18:56:00 KORD 0.81
1999-01-27 20:00:00 1999-01-27 19:56:00 KORD 0.01
1999-01-27 21:00:00 1999-01-27 20:56:00 KORD -0.59
1999-01-27 21:00:00 1999-01-27 21:18:00 KORD -0.99
1999-01-27 22:00:00 1999-01-27 21:56:00 KORD -0.59
1999-01-27 23:00:00 1999-01-27 22:56:00 KORD -0.59
注意
read_csv有一个fast_path用于解析iso8601格式的日期时间字符串,例如“2000-01-01T00:01:02 + 00:00”和类似的变体。如果您可以安排您的数据以此格式存储数据时间,加载时间将显着更快,观察到约20倍。
注意
当传递一个dict作为parse_dates参数时,不保证前置列的顺序,因为dict对象不对它们的键施加排序。在Python 2.7+上,如果这对你很重要,你可以使用collections.OrderedDict而不是普通的dict。因此,当对于'parse_dates'与index_col参数结合使用dict时,最好将index_col指定为列标签,而不是作为结果的索引帧。
Date Parsing Functions¶
最后,解析器允许您指定自定义date_parser
函数,以充分利用日期解析API的灵活性:
In [102]: import pandas.io.date_converters as conv
In [103]: df = pd.read_csv('tmp.csv', header=None, parse_dates=date_spec,
.....: date_parser=conv.parse_date_time)
.....:
In [104]: df
Out[104]:
nominal actual 0 4
0 1999-01-27 19:00:00 1999-01-27 18:56:00 KORD 0.81
1 1999-01-27 20:00:00 1999-01-27 19:56:00 KORD 0.01
2 1999-01-27 21:00:00 1999-01-27 20:56:00 KORD -0.59
3 1999-01-27 21:00:00 1999-01-27 21:18:00 KORD -0.99
4 1999-01-27 22:00:00 1999-01-27 21:56:00 KORD -0.59
5 1999-01-27 23:00:00 1999-01-27 22:56:00 KORD -0.59
Pandas将尝试以三种不同的方式调用date_parser
函数。如果引发异常,则尝试下一个异常:
- 首先使用parse_dates(例如,
date_parser(['2013',])定义一个或多个数组作为参数调用
date_parser
'2013'], ['1', '2']) - 如果#1失败,则调用
date_parser
,所有列按行连接到单个数组中(例如,date_parser(['2013 1' , '2013 2'])
) - 如果#2失败,则对于具有来自parse_dates指示的列中的一个或多个字符串参数的每一行调用
date_parser
一次(例如,date_parser 2013“,” '2')的第一行(
2013',
'1') 用于第二个,等等)
注意,在性能方面,你应该尝试这些方法按顺序解析日期:
- 尝试使用
infer_datetime_format=True
(请参见下面部分)推断格式 - 如果您知道格式,请使用
pd.to_datetime()
:date_parser = lambda x: pd.to_datetime , format = ...)
- 如果您有非标准格式,请使用自定义
date_parser
函数。为了获得最佳性能,这应该是向量化的,即它应该接受数组作为参数。
您可以在date_converters.py
中探索日期解析功能,并添加自己的日期解析功能。我们希望将这个模块变成一个社区支持的日期/时间解析器集合。为了让您入门,date_converters.py
包含用于解析双日期和时间列,年/月/日列和年/月/日/小时/分/秒列的功能。它还包含一个generic_parser
函数,因此您可以使用处理单个日期而不是整个数组的函数来对其进行curry。
Inferring Datetime Format¶
如果您为某些或所有列启用了parse_dates
,并且datetime字符串都采用相同的格式,则可以通过设置infer_datetime_format=True
。如果设置,pandas将尝试猜测datetime字符串的格式,然后使用更快的方式解析字符串。观察到5-10x解析速度。pandas将回退到通常的解析,如果格式不能猜到或者猜测的格式不能正确解析整个字符串列。因此,一般来说,如果启用infer_datetime_format
,则不应产生任何负面结果。
以下是可以猜测的日期时间字符串的一些示例(全部表示2011年12月30日00:00:00)
- “20111230”
- “2011/12/30”
- “20111230 00:00:00”
- “12/30/2011 00:00:00”
- “30 / Dec / 2011 00:00:00”
- “30 / December / 2011 00:00:00”
infer_datetime_format
对dayfirst
敏感。使用dayfirst=True
,它会猜到“01/12/2011”为12月1日。使用dayfirst=False
(默认),它会猜到“01/12/2011”为1月12日。
# Try to infer the format for the index column
In [105]: df = pd.read_csv('foo.csv', index_col=0, parse_dates=True,
.....: infer_datetime_format=True)
.....:
In [106]: df
Out[106]:
A B C
date
2009-01-01 a 1 2
2009-01-02 b 3 4
2009-01-03 c 4 5
International Date Formats¶
虽然美国日期格式通常为MM / DD / YYYY,但许多国际格式使用DD / MM / YYYY。为方便起见,提供了dayfirst
关键字:
In [107]: print(open('tmp.csv').read())
date,value,cat
1/6/2000,5,a
2/6/2000,10,b
3/6/2000,15,c
In [108]: pd.read_csv('tmp.csv', parse_dates=[0])
Out[108]:
date value cat
0 2000-01-06 5 a
1 2000-02-06 10 b
2 2000-03-06 15 c
In [109]: pd.read_csv('tmp.csv', dayfirst=True, parse_dates=[0])
Out[109]:
date value cat
0 2000-06-01 5 a
1 2000-06-02 10 b
2 2000-06-03 15 c
Specifying method for floating-point conversion¶
可以指定参数float_precision
,以便在使用C引擎进行解析期间使用特定的浮点转换器。选项是普通转换器,高精度转换器和往返转换器(在写入文件后保证往返值)。例如:
In [110]: val = '0.3066101993807095471566981359501369297504425048828125'
In [111]: data = 'a,b,c\n1,2,{0}'.format(val)
In [112]: abs(pd.read_csv(StringIO(data), engine='c', float_precision=None)['c'][0] - float(val))
Out[112]: 1.1102230246251565e-16
In [113]: abs(pd.read_csv(StringIO(data), engine='c', float_precision='high')['c'][0] - float(val))
Out[113]: 5.5511151231257827e-17
In [114]: abs(pd.read_csv(StringIO(data), engine='c', float_precision='round_trip')['c'][0] - float(val))
Out[114]: 0.0
Thousand Separators¶
对于已使用千位分隔符写入的大数字,可以将thousands
关键字设置为长度为1的字符串,以便整数将被正确解析:
默认情况下,带有千位分隔符的数字将被解析为字符串
In [115]: print(open('tmp.csv').read())
ID|level|category
Patient1|123,000|x
Patient2|23,000|y
Patient3|1,234,018|z
In [116]: df = pd.read_csv('tmp.csv', sep='|')
In [117]: df
Out[117]:
ID level category
0 Patient1 123,000 x
1 Patient2 23,000 y
2 Patient3 1,234,018 z
In [118]: df.level.dtype
Out[118]: dtype('O')
thousands
关键字允许正确解析整数
In [119]: print(open('tmp.csv').read())
ID|level|category
Patient1|123,000|x
Patient2|23,000|y
Patient3|1,234,018|z
In [120]: df = pd.read_csv('tmp.csv', sep='|', thousands=',')
In [121]: df
Out[121]:
ID level category
0 Patient1 123000 x
1 Patient2 23000 y
2 Patient3 1234018 z
In [122]: df.level.dtype
Out[122]: dtype('int64')
NA Values¶
要控制哪些值被解析为缺失值(由NaN
表示),请在na_values
中指定一个字符串。如果指定字符串列表,则其中的所有值都将被视为缺少值。如果您指定一个数字(float
,例如5.0
或integer
,例如5
),也将意味着缺失值(在这种情况下,有效地[5.0,5]
被识别为NaN
。
要完全覆盖被识别为缺少的默认值,请指定keep_default_na=False
。The default NaN
recognized values are ['-1.#IND', '1.#QNAN', '1.#IND', '-1.#QNAN', '#N/A','N/A', 'NA', '#NA', 'NULL', 'NaN', '-NaN', 'nan', '-nan']
. 虽然长度为0的字符串''
不包含在默认的NaN
值列表中,但仍被视为缺失值。
read_csv(path, na_values=[5])
5
,5.0
被解释为数字被识别为NaN
read_csv(path, keep_default_na=False, na_values=[""])
只有空字段为NaN
read_csv(path, keep_default_na=False, na_values=["NA", "0"])
只有NA
和0
作为字符串是NaN
read_csv(path, na_values=["Nope"])
字符串"Nope"
被识别为NaN
Infinity¶
inf
的值将被解析为np.inf
(正无穷大),-inf
为-np.inf
这些将忽略该值的情况,意思是Inf
,也将被解析为np.inf
。
Returning Series¶
使用squeeze
关键字,解析器将返回单个列作为Series
的输出:
In [123]: print(open('tmp.csv').read())
level
Patient1,123000
Patient2,23000
Patient3,1234018
In [124]: output = pd.read_csv('tmp.csv', squeeze=True)
In [125]: output
Out[125]:
Patient1 123000
Patient2 23000
Patient3 1234018
Name: level, dtype: int64
In [126]: type(output)
Out[126]: pandas.core.series.Series
Boolean values¶
公共值True
,False
,TRUE
和FALSE
都被识别为布尔值。有时你想要识别一些其他值为布尔。为此,请使用true_values
和false_values
选项:
In [127]: data= 'a,b,c\n1,Yes,2\n3,No,4'
In [128]: print(data)
a,b,c
1,Yes,2
3,No,4
In [129]: pd.read_csv(StringIO(data))
Out[129]:
a b c
0 1 Yes 2
1 3 No 4
In [130]: pd.read_csv(StringIO(data), true_values=['Yes'], false_values=['No'])
Out[130]:
a b c
0 1 True 2
1 3 False 4
Handling “bad” lines¶
某些文件可能包含字段太少或太多的格式不正确的行。具有太少字段的行将在尾部字段中填充NA值。过多的行会默认产生错误:
In [27]: data = 'a,b,c\n1,2,3\n4,5,6,7\n8,9,10'
In [28]: pd.read_csv(StringIO(data))
---------------------------------------------------------------------------
CParserError Traceback (most recent call last)
CParserError: Error tokenizing data. C error: Expected 3 fields in line 3, saw 4
你可以选择跳过坏行:
In [29]: pd.read_csv(StringIO(data), error_bad_lines=False)
Skipping line 3: expected 3 fields, saw 4
Out[29]:
a b c
0 1 2 3
1 8 9 10
Quoting and Escape Characters¶
嵌入字段中的引号(和其他转义字符)可以以任何数量的方式处理。一种方法是使用反斜杠;要正确解析此数据,您应该传递escapechar
选项:
In [131]: data = 'a,b\n"hello, \\"Bob\\", nice to see you",5'
In [132]: print(data)
a,b
"hello, \"Bob\", nice to see you",5
In [133]: pd.read_csv(StringIO(data), escapechar='\\')
Out[133]:
a b
0 hello, "Bob", nice to see you 5
Files with Fixed Width Columns¶
当read_csv
读取定界数据时,read_fwf()
函数适用于已知和固定列宽的数据文件。read_fwf
的函数参数与具有两个额外参数的read_csv大致相同:
colspecs
:将每行的固定宽度字段的范围作为半开间隔(即,从[from,to])的对(元组)列表。字符串值“infer”可以用于指示解析器尝试从数据的前100行中检测列规范。默认行为,如果没有指定,是推断。widths
:如果间隔是连续的,可以使用字段宽度列表来代替“colspecs”。
考虑一个典型的固定宽度数据文件:
In [134]: print(open('bar.csv').read())
id8141 360.242940 149.910199 11950.7
id1594 444.953632 166.985655 11788.4
id1849 364.136849 183.628767 11806.2
id1230 413.836124 184.375703 11916.8
id1948 502.953953 173.237159 12468.3
为了将该文件解析为DataFrame,我们只需要向read_fwf函数提供列规范以及文件名:
#Column specifications are a list of half-intervals
In [135]: colspecs = [(0, 6), (8, 20), (21, 33), (34, 43)]
In [136]: df = pd.read_fwf('bar.csv', colspecs=colspecs, header=None, index_col=0)
In [137]: df
Out[137]:
1 2 3
0
id8141 360.242940 149.910199 11950.7
id1594 444.953632 166.985655 11788.4
id1849 364.136849 183.628767 11806.2
id1230 413.836124 184.375703 11916.8
id1948 502.953953 173.237159 12468.3
注意解析器如何自动选择列名X.当指定header=None
参数时,
#Widths are a list of integers
In [138]: widths = [6, 14, 13, 10]
In [139]: df = pd.read_fwf('bar.csv', widths=widths, header=None)
In [140]: df
Out[140]:
0 1 2 3
0 id8141 360.242940 149.910199 11950.7
1 id1594 444.953632 166.985655 11788.4
2 id1849 364.136849 183.628767 11806.2
3 id1230 413.836124 184.375703 11916.8
4 id1948 502.953953 173.237159 12468.3
解析器将处理列周围的额外的空白空间,因此在文件中的列之间可以有额外的分隔。
版本0.13.0中的新功能。
默认情况下,read_fwf
会尝试使用文件的前100行来推断文件的colspecs
。它只能在列对齐并通过提供的delimiter
(默认分隔符为空格)正确分隔的情况下才能执行。
In [141]: df = pd.read_fwf('bar.csv', header=None, index_col=0)
In [142]: df
Out[142]:
1 2 3
0
id8141 360.242940 149.910199 11950.7
id1594 444.953632 166.985655 11788.4
id1849 364.136849 183.628767 11806.2
id1230 413.836124 184.375703 11916.8
id1948 502.953953 173.237159 12468.3
Indexes¶
Files with an “implicit” index column¶
考虑一个文件在头中少于一个数据列数:
In [143]: print(open('foo.csv').read())
A,B,C
20090101,a,1,2
20090102,b,3,4
20090103,c,4,5
在这种特殊情况下,read_csv
假定第一列将用作DataFrame的索引:
In [144]: pd.read_csv('foo.csv')
Out[144]:
A B C
20090101 a 1 2
20090102 b 3 4
20090103 c 4 5
请注意,日期不会自动解析。在这种情况下,你需要像以前一样做:
In [145]: df = pd.read_csv('foo.csv', parse_dates=True)
In [146]: df.index
Out[146]: DatetimeIndex(['2009-01-01', '2009-01-02', '2009-01-03'], dtype='datetime64[ns]', freq=None)
Reading an index with a MultiIndex
¶
假设您的数据由两列索引:
In [147]: print(open('data/mindex_ex.csv').read())
year,indiv,zit,xit
1977,"A",1.2,.6
1977,"B",1.5,.5
1977,"C",1.7,.8
1978,"A",.2,.06
1978,"B",.7,.2
1978,"C",.8,.3
1978,"D",.9,.5
1978,"E",1.4,.9
1979,"C",.2,.15
1979,"D",.14,.05
1979,"E",.5,.15
1979,"F",1.2,.5
1979,"G",3.4,1.9
1979,"H",5.4,2.7
1979,"I",6.4,1.2
read_csv
和read_table
的index_col
参数可以使用列号列表将多个列转换为MultiIndex
返回对象的索引:
In [148]: df = pd.read_csv("data/mindex_ex.csv", index_col=[0,1])
In [149]: df
Out[149]:
zit xit
year indiv
1977 A 1.20 0.60
B 1.50 0.50
C 1.70 0.80
1978 A 0.20 0.06
B 0.70 0.20
C 0.80 0.30
D 0.90 0.50
E 1.40 0.90
1979 C 0.20 0.15
D 0.14 0.05
E 0.50 0.15
F 1.20 0.50
G 3.40 1.90
H 5.40 2.70
I 6.40 1.20
In [150]: df.ix[1978]
Out[150]:
zit xit
indiv
A 0.2 0.06
B 0.7 0.20
C 0.8 0.30
D 0.9 0.50
E 1.4 0.90
Reading columns with a MultiIndex
¶
通过指定header
参数的行位置列表,您可以在MultiIndex
中读取列。指定非连续行将跳过中间行。为了具有tingleizing列的pre-0.13行为,请指定tupleize_cols=True
。
In [151]: from pandas.util.testing import makeCustomDataframe as mkdf
In [152]: df = mkdf(5,3,r_idx_nlevels=2,c_idx_nlevels=4)
In [153]: df.to_csv('mi.csv')
In [154]: print(open('mi.csv').read())
C0,,C_l0_g0,C_l0_g1,C_l0_g2
C1,,C_l1_g0,C_l1_g1,C_l1_g2
C2,,C_l2_g0,C_l2_g1,C_l2_g2
C3,,C_l3_g0,C_l3_g1,C_l3_g2
R0,R1,,,
R_l0_g0,R_l1_g0,R0C0,R0C1,R0C2
R_l0_g1,R_l1_g1,R1C0,R1C1,R1C2
R_l0_g2,R_l1_g2,R2C0,R2C1,R2C2
R_l0_g3,R_l1_g3,R3C0,R3C1,R3C2
R_l0_g4,R_l1_g4,R4C0,R4C1,R4C2
In [155]: pd.read_csv('mi.csv',header=[0,1,2,3],index_col=[0,1])
Out[155]:
C0 C_l0_g0 C_l0_g1 C_l0_g2
C1 C_l1_g0 C_l1_g1 C_l1_g2
C2 C_l2_g0 C_l2_g1 C_l2_g2
C3 C_l3_g0 C_l3_g1 C_l3_g2
R0 R1
R_l0_g0 R_l1_g0 R0C0 R0C1 R0C2
R_l0_g1 R_l1_g1 R1C0 R1C1 R1C2
R_l0_g2 R_l1_g2 R2C0 R2C1 R2C2
R_l0_g3 R_l1_g3 R3C0 R3C1 R3C2
R_l0_g4 R_l1_g4 R4C0 R4C1 R4C2
从0.13.0开始,read_csv
将能够解释更常见的多列索引格式。
In [156]: print(open('mi2.csv').read())
,a,a,a,b,c,c
,q,r,s,t,u,v
one,1,2,3,4,5,6
two,7,8,9,10,11,12
In [157]: pd.read_csv('mi2.csv',header=[0,1],index_col=0)
Out[157]:
a b c
q r s t u v
one 1 2 3 4 5 6
two 7 8 9 10 11 12
Note: If an index_col
is not specified (e.g. you don’t have an index, or wrote it with df.to_csv(..., index=False
), then any names
on the columns index will be lost.
Automatically “sniffing” the delimiter¶
read_csv
能够推断定界(不一定是逗号分隔)文件,因为pandas使用csv模块的csv.Sniffer
类。为此,您必须指定sep=None
。
In [158]: print(open('tmp2.sv').read())
:0:1:2:3
0:0.469112299907:-0.282863344329:-1.50905850317:-1.13563237102
1:1.21211202502:-0.173214649053:0.119208711297:-1.04423596628
2:-0.861848963348:-2.10456921889:-0.494929274069:1.07180380704
3:0.721555162244:-0.70677113363:-1.03957498511:0.271859885543
4:-0.424972329789:0.567020349794:0.276232019278:-1.08740069129
5:-0.673689708088:0.113648409689:-1.47842655244:0.524987667115
6:0.40470521868:0.57704598592:-1.71500201611:-1.03926848351
7:-0.370646858236:-1.15789225064:-1.34431181273:0.844885141425
8:1.07576978372:-0.10904997528:1.64356307036:-1.46938795954
9:0.357020564133:-0.67460010373:-1.77690371697:-0.968913812447
In [159]: pd.read_csv('tmp2.sv', sep=None, engine='python')
Out[159]:
Unnamed: 0 0 1 2 3
0 0 0.469112 -0.282863 -1.509059 -1.135632
1 1 1.212112 -0.173215 0.119209 -1.044236
2 2 -0.861849 -2.104569 -0.494929 1.071804
3 3 0.721555 -0.706771 -1.039575 0.271860
4 4 -0.424972 0.567020 0.276232 -1.087401
5 5 -0.673690 0.113648 -1.478427 0.524988
6 6 0.404705 0.577046 -1.715002 -1.039268
7 7 -0.370647 -1.157892 -1.344312 0.844885
8 8 1.075770 -0.109050 1.643563 -1.469388
9 9 0.357021 -0.674600 -1.776904 -0.968914
Iterating through files chunk by chunk¶
假设您希望延迟遍历一个(可能非常大)的文件,而不是将整个文件读入内存,如下所示:
In [160]: print(open('tmp.sv').read())
|0|1|2|3
0|0.469112299907|-0.282863344329|-1.50905850317|-1.13563237102
1|1.21211202502|-0.173214649053|0.119208711297|-1.04423596628
2|-0.861848963348|-2.10456921889|-0.494929274069|1.07180380704
3|0.721555162244|-0.70677113363|-1.03957498511|0.271859885543
4|-0.424972329789|0.567020349794|0.276232019278|-1.08740069129
5|-0.673689708088|0.113648409689|-1.47842655244|0.524987667115
6|0.40470521868|0.57704598592|-1.71500201611|-1.03926848351
7|-0.370646858236|-1.15789225064|-1.34431181273|0.844885141425
8|1.07576978372|-0.10904997528|1.64356307036|-1.46938795954
9|0.357020564133|-0.67460010373|-1.77690371697|-0.968913812447
In [161]: table = pd.read_table('tmp.sv', sep='|')
In [162]: table
Out[162]:
Unnamed: 0 0 1 2 3
0 0 0.469112 -0.282863 -1.509059 -1.135632
1 1 1.212112 -0.173215 0.119209 -1.044236
2 2 -0.861849 -2.104569 -0.494929 1.071804
3 3 0.721555 -0.706771 -1.039575 0.271860
4 4 -0.424972 0.567020 0.276232 -1.087401
5 5 -0.673690 0.113648 -1.478427 0.524988
6 6 0.404705 0.577046 -1.715002 -1.039268
7 7 -0.370647 -1.157892 -1.344312 0.844885
8 8 1.075770 -0.109050 1.643563 -1.469388
9 9 0.357021 -0.674600 -1.776904 -0.968914
通过指定chunksize
到read_csv
或read_table
,返回值将是TextFileReader
类型的可迭代对象:
In [163]: reader = pd.read_table('tmp.sv', sep='|', chunksize=4)
In [164]: reader
Out[164]: <pandas.io.parsers.TextFileReader at 0x7ff27e15a450>
In [165]: for chunk in reader:
.....: print(chunk)
.....:
Unnamed: 0 0 1 2 3
0 0 0.469112 -0.282863 -1.509059 -1.135632
1 1 1.212112 -0.173215 0.119209 -1.044236
2 2 -0.861849 -2.104569 -0.494929 1.071804
3 3 0.721555 -0.706771 -1.039575 0.271860
Unnamed: 0 0 1 2 3
4 4 -0.424972 0.567020 0.276232 -1.087401
5 5 -0.673690 0.113648 -1.478427 0.524988
6 6 0.404705 0.577046 -1.715002 -1.039268
7 7 -0.370647 -1.157892 -1.344312 0.844885
Unnamed: 0 0 1 2 3
8 8 1.075770 -0.10905 1.643563 -1.469388
9 9 0.357021 -0.67460 -1.776904 -0.968914
指定iterator=True
也会返回TextFileReader
对象:
In [166]: reader = pd.read_table('tmp.sv', sep='|', iterator=True)
In [167]: reader.get_chunk(5)
Out[167]:
Unnamed: 0 0 1 2 3
0 0 0.469112 -0.282863 -1.509059 -1.135632
1 1 1.212112 -0.173215 0.119209 -1.044236
2 2 -0.861849 -2.104569 -0.494929 1.071804
3 3 0.721555 -0.706771 -1.039575 0.271860
4 4 -0.424972 0.567020 0.276232 -1.087401
Specifying the parser engine¶
引擎下pandas使用一个快速和高效的解析器实现在C以及一个python实现,目前更功能完整。在可能的情况下,pandas使用C解析器(指定为engine='c'
),但如果指定了C不支持的选项,则可能会回到python。目前,C不受支持的选项包括:
sep
而不是单个字符(例如,regex分隔符)skipfooter
sep=None
与delim_whitespace=False
指定以上任何选项将产生ParserWarning
,除非使用engine='python'
明确选择了python引擎。
Writing out Data¶
Writing to CSV format¶
Series和DataFrame对象具有一个实例方法to_csv
,它允许将对象的内容存储为逗号分隔值文件。该函数接受一些参数。只有第一个是必需的。
path_or_buf
:要写入的文件或StringIO的字符串路径sep
:输出文件的字段分隔符(默认为“,”)na_rep
:缺少值的字符串表示形式(默认为'')float_format
:格式化浮点数字符串cols
:要写入的列(默认值为无)header
:是否写出列名(默认为True)index
:是否写入行(索引)名称(默认为True)index_label
:索引列的列标签(如果需要)。如果无(默认),头和index为True,则使用索引名称。(如果DataFrame使用MultiIndex,应该给出一个序列)。mode
:Python写模式,默认为'w'encoding
:表示要使用的编码的字符串,如果内容是非ASCII的,对于python版本3之前line_terminator
:表示行结束的字符序列(默认'\ n')quoting
:在csv模块中设置引用规则(默认为csv.QUOTE_MINIMAL)。注意,如果你设置了一个float_format,那么浮点数被转换为字符串,csv.QUOTE_NONNUMERIC会将它们作为非数字quotechar
:用于引用字段的字符(默认'“')doublequote
:在字段中控制quotechar
的引用(默认值为True)escapechar
:适当时用于转义sep
和quotechar
的字符(默认值为None)chunksize
:每次写入的行数tupleize_cols
:如果为False(默认值),则写为元组列表,否则以适用于read_csv
date_format
:格式化datetime对象的字符串
Writing a formatted string¶
DataFrame对象有一个实例方法to_string
,它允许控制对象的字符串表示。所有参数都是可选的:
buf
默认值无,例如StringIO对象columns
默认值无,要写入的列col_space
默认值无,每列的最小宽度。na_rep
默认NaN
,表示NA值formatters
default无,函数的字典(按列),每个函数接受单个参数并返回格式化的字符串float_format
default无,一个函数,它接受一个(float)参数并返回一个格式化的字符串;以应用于DataFrame中的浮动。sparsify
default True,对于具有层次索引的DataFrame,设置为False以在每行打印每个多索引键。index_names
默认为True,将打印索引的名称index
default True,将打印索引(即行标签)header
default True,将打印列标签justify
默认left
,将左对齐或右对齐打印列标题
Series对象还有一个to_string
方法,但只有buf
,na_rep
,float_format
参数。还有一个length
参数,如果设置为True
,将另外输出系列的长度。
JSON¶
读取和写入JSON
格式的文件和字符串。
Writing JSON¶
可以将Series
或DataFrame
转换为有效的JSON字符串。使用可选参数to_json
:
path_or_buf
:写入输出的路径名或缓冲区可以是None
,在这种情况下返回JSON字符串orient
:- 系列:
- 默认为
index
- 允许值为{
split
,records
,index
}
- 默认为
- DataFrame
- 默认为
columns
- 允许值为{
split
,records
,index
,columns
,values
- 默认为
JSON字符串的格式
split
dict like {index - > [index],columns - > [columns],data - > [values]} records
列表像[{column - > value},...,{column - > value}] index
dict like {index - > {column - > value}} columns
dict like {column - > {index - > value}} values
只是值数组 date_format
:字符串,日期转换类型,“epoch”表示时间戳,“iso”表示ISO8601。double_precision
:编码浮点值时使用的小数位数,默认值为10。force_ascii
:强制编码字符串为ASCII,默认为True。date_unit
:要编码的时间单位,支配时间戳和ISO8601精度。分别为秒,毫秒,微秒和纳秒的's','ms','us'或'ns'之一。默认值“ms”。default_handler
:如果对象无法转换为适当的JSON格式,则调用的处理程序。采用单个参数,它是要转换的对象,并返回可序列化对象。lines
:如果records
orient,则将每行的每条记录作为json写入。
Note NaN
‘s, NaT
‘s and None
will be converted to null
and datetime
objects will be converted based on the date_format
and date_unit
parameters.
In [168]: dfj = pd.DataFrame(randn(5, 2), columns=list('AB'))
In [169]: json = dfj.to_json()
In [170]: json
Out[170]: '{"A":{"0":-1.2945235903,"1":0.2766617129,"2":-0.0139597524,"3":-0.0061535699,"4":0.8957173022},"B":{"0":0.4137381054,"1":-0.472034511,"2":-0.3625429925,"3":-0.923060654,"4":0.8052440254}}'
Orient Options¶
生成的JSON文件/字符串的格式有多种不同的选项。考虑下面的DataFrame和Series:
In [171]: dfjo = pd.DataFrame(dict(A=range(1, 4), B=range(4, 7), C=range(7, 10)),
.....: columns=list('ABC'), index=list('xyz'))
.....:
In [172]: dfjo
Out[172]:
A B C
x 1 4 7
y 2 5 8
z 3 6 9
In [173]: sjo = pd.Series(dict(x=15, y=16, z=17), name='D')
In [174]: sjo
Out[174]:
x 15
y 16
z 17
Name: D, dtype: int64
面向列(DataFrame
的默认值)将数据序列化为以列标签作为主索引的嵌套JSON对象:
In [175]: dfjo.to_json(orient="columns")
Out[175]: '{"A":{"x":1,"y":2,"z":3},"B":{"x":4,"y":5,"z":6},"C":{"x":7,"y":8,"z":9}}'
面向索引(类似于Series
的默认值)类似于面向列,但索引标签现在是主要的:
In [176]: dfjo.to_json(orient="index")
Out[176]: '{"x":{"A":1,"B":4,"C":7},"y":{"A":2,"B":5,"C":8},"z":{"A":3,"B":6,"C":9}}'
In [177]: sjo.to_json(orient="index")
Out[177]: '{"x":15,"y":16,"z":17}'
面向记录将数据序列化为列 - >值记录的JSON数组,不包括索引标签。这对于将DataFrame数据传递到绘图库很有用,例如JavaScript库d3.js:
In [178]: dfjo.to_json(orient="records")
Out[178]: '[{"A":1,"B":4,"C":7},{"A":2,"B":5,"C":8},{"A":3,"B":6,"C":9}]'
In [179]: sjo.to_json(orient="records")
Out[179]: '[15,16,17]'
面向价值是一个裸体选项,仅序列化为嵌套JSON数组的值,不包括列和索引标签:
In [180]: dfjo.to_json(orient="values")
Out[180]: '[[1,4,7],[2,5,8],[3,6,9]]'
面向分组序列化为包含值,索引和列的单独条目的JSON对象。Series
也包括名称:
In [181]: dfjo.to_json(orient="split")
Out[181]: '{"columns":["A","B","C"],"index":["x","y","z"],"data":[[1,4,7],[2,5,8],[3,6,9]]}'
In [182]: sjo.to_json(orient="split")
Out[182]: '{"name":"D","index":["x","y","z"],"data":[15,16,17]}'
注意
编码到JSON对象的任何orient选项将不会在往返序列化期间保留索引和列标签的顺序。如果您希望保留标签排序,请使用拆分选项,因为它使用有序容器。
Date Handling¶
以ISO日期格式写入
In [183]: dfd = pd.DataFrame(randn(5, 2), columns=list('AB'))
In [184]: dfd['date'] = pd.Timestamp('20130101')
In [185]: dfd = dfd.sort_index(1, ascending=False)
In [186]: json = dfd.to_json(date_format='iso')
In [187]: json
Out[187]: '{"date":{"0":"2013-01-01T00:00:00.000Z","1":"2013-01-01T00:00:00.000Z","2":"2013-01-01T00:00:00.000Z","3":"2013-01-01T00:00:00.000Z","4":"2013-01-01T00:00:00.000Z"},"B":{"0":2.5656459463,"1":1.3403088498,"2":-0.2261692849,"3":0.8138502857,"4":-0.8273169356},"A":{"0":-1.2064117817,"1":1.4312559863,"2":-1.1702987971,"3":0.4108345112,"4":0.1320031703}}'
以ISO日期格式写入,以微秒为单位
In [188]: json = dfd.to_json(date_format='iso', date_unit='us')
In [189]: json
Out[189]: '{"date":{"0":"2013-01-01T00:00:00.000000Z","1":"2013-01-01T00:00:00.000000Z","2":"2013-01-01T00:00:00.000000Z","3":"2013-01-01T00:00:00.000000Z","4":"2013-01-01T00:00:00.000000Z"},"B":{"0":2.5656459463,"1":1.3403088498,"2":-0.2261692849,"3":0.8138502857,"4":-0.8273169356},"A":{"0":-1.2064117817,"1":1.4312559863,"2":-1.1702987971,"3":0.4108345112,"4":0.1320031703}}'
Epoch时间戳,以秒为单位
In [190]: json = dfd.to_json(date_format='epoch', date_unit='s')
In [191]: json
Out[191]: '{"date":{"0":1356998400,"1":1356998400,"2":1356998400,"3":1356998400,"4":1356998400},"B":{"0":2.5656459463,"1":1.3403088498,"2":-0.2261692849,"3":0.8138502857,"4":-0.8273169356},"A":{"0":-1.2064117817,"1":1.4312559863,"2":-1.1702987971,"3":0.4108345112,"4":0.1320031703}}'
写入文件,包含日期索引和日期列
In [192]: dfj2 = dfj.copy()
In [193]: dfj2['date'] = pd.Timestamp('20130101')
In [194]: dfj2['ints'] = list(range(5))
In [195]: dfj2['bools'] = True
In [196]: dfj2.index = pd.date_range('20130101', periods=5)
In [197]: dfj2.to_json('test.json')
In [198]: open('test.json').read()
Out[198]: '{"A":{"1356998400000":-1.2945235903,"1357084800000":0.2766617129,"1357171200000":-0.0139597524,"1357257600000":-0.0061535699,"1357344000000":0.8957173022},"B":{"1356998400000":0.4137381054,"1357084800000":-0.472034511,"1357171200000":-0.3625429925,"1357257600000":-0.923060654,"1357344000000":0.8052440254},"date":{"1356998400000":1356998400000,"1357084800000":1356998400000,"1357171200000":1356998400000,"1357257600000":1356998400000,"1357344000000":1356998400000},"ints":{"1356998400000":0,"1357084800000":1,"1357171200000":2,"1357257600000":3,"1357344000000":4},"bools":{"1356998400000":true,"1357084800000":true,"1357171200000":true,"1357257600000":true,"1357344000000":true}}'
Fallback Behavior¶
如果JSON序列化器不能直接处理容器内容,它将以以下方式回退:
- 如果dtype不被支持(例如
np.complex
),那么将为每个值调用default_handler
(如果提供),否则会引发异常。 - 如果对象不受支持,它将尝试以下操作:
- 检查对象是否定义了
toDict
方法并调用它。toDict
方法应返回一个dict
,然后将JSON序列化。 - 调用
default_handler
(如果提供)。 - 通过遍历其内容将对象转换为
dict
。但是,这通常会失败并显示OverflowError
或给出意外的结果。
- 检查对象是否定义了
一般来说,不受支持的对象或类型的最佳方法是提供一个default_handler
。例如:
DataFrame([1.0, 2.0, complex(1.0, 2.0)]).to_json() # raises
RuntimeError: Unhandled numpy dtype 15
可以通过指定一个简单的default_handler
来处理:
In [199]: pd.DataFrame([1.0, 2.0, complex(1.0, 2.0)]).to_json(default_handler=str)
Out[199]: '{"0":{"0":"(1+0j)","1":"(2+0j)","2":"(1+2j)"}}'
Reading JSON¶
读取JSON字符串到pandas对象可以取多个参数。如果未提供typ
或None
,解析器将尝试解析DataFrame
。要明确强制Series
解析,请传递typ=series
filepath_or_buffer
:a VALID JSON字符串或文件句柄/ StringIO。字符串可以是URL。有效的URL方案包括http,ftp,S3和文件。对于文件URL,需要主机。例如,本地文件可以是file://localhost/path/to/table.jsontyp
:要恢复的对象类型(系列或框架),默认'frame'orient
:- 系列:
- 默认为
index
- 允许值为{
split
,records
,index
}
- 默认为
- DataFrame
- 默认为
columns
- 允许值为{
split
,records
,index
,columns
,values
- 默认为
JSON字符串的格式
split
dict like {index - > [index],columns - > [columns],data - > [values]} records
列表像[{column - > value},...,{column - > value}] index
dict like {index - > {column - > value}} columns
dict like {column - > {index - > value}} values
只是值数组 dtype
:如果为True,推断dtypes,如果一个列的字典到dtype,然后使用那些,如果False,则不推断dtypes在所有,默认为True,仅适用于数据convert_axes
:boolean,尝试将轴转换为正确的dtypes,默认值为Trueconvert_dates
:解析日期的列列表;如果为True,则尝试解析类似日期的列,默认值为Truekeep_default_dates
:boolean,default True。如果解析日期,则解析默认的日期样列numpy
:直接解码为numpy数组。默认为False;仅支持数字数据,但标签可能是非数字的。还要注意,如果numpy=True
,JSON排序MUSTprecise_float
:boolean,默认False
。设置为在将字符串解码为双精度值时启用更高精度(strtod)函数的使用。默认值(False
)是使用快速但不太精确的内置功能date_unit
:string,用于检测转换日期的时间戳单位。默认值无。默认情况下,将检测时间戳精度,如果不需要,则通过's','ms','us'或'ns'之一分别强制时间戳精度为秒,毫秒,微秒或纳秒。lines
:每行将文件读取为一个json对象。encoding
:用于解码py3字节的编码。
如果JSON不可解析,解析器将产生ValueError/TypeError/AssertionError
之一。
如果在编码为JSON时使用非默认orient
,则必须在此处传递相同的选项,以便解码产生合理的结果,有关概述,请参见Orient选项。
Data Conversion¶
默认为convert_axes=True
,dtype=True
和convert_dates=True
会尝试解析轴,类型,包括日期。如果您需要覆盖特定的dtypes,请传递一个dict到dtype
。如果您需要在轴中保留字符串状数字(例如“1”,“2”),则只应将convert_axes
设置为False
。
注意
如果convert_dates=True
,且数据和/或列标签显示为“日期样”,则大整数值可以转换为日期。确切的阈值取决于指定的date_unit
。“日期样”表示列标签满足以下条件之一:
- 它以
'_at'
结尾- 它以
'_time'
结尾- 它从
'timestamp'
开始- 它是
'modified'
- 它是
'date'
警告
当读取JSON数据时,自动强制转换为dtypes有一些怪癖:
- 可以按照与序列化不同的顺序重建索引,也就是说,返回的顺序不能保证与序列化之前相同
- 如果可以安全地执行,则
float
数据的列将转换为integer
。一列1.
- bool列将在重建时转换为
integer
因此,有时您可能需要通过dtype
关键字参数指定特定的dtypes。
从JSON字符串读取:
In [200]: pd.read_json(json)
Out[200]:
A B date
0 -1.206412 2.565646 2013-01-01
1 1.431256 1.340309 2013-01-01
2 -1.170299 -0.226169 2013-01-01
3 0.410835 0.813850 2013-01-01
4 0.132003 -0.827317 2013-01-01
从文件读取:
In [201]: pd.read_json('test.json')
Out[201]:
A B bools date ints
2013-01-01 -1.294524 0.413738 True 2013-01-01 0
2013-01-02 0.276662 -0.472035 True 2013-01-01 1
2013-01-03 -0.013960 -0.362543 True 2013-01-01 2
2013-01-04 -0.006154 -0.923061 True 2013-01-01 3
2013-01-05 0.895717 0.805244 True 2013-01-01 4
不转换任何数据(但仍然转换轴和日期):
In [202]: pd.read_json('test.json', dtype=object).dtypes
Out[202]:
A object
B object
bools object
date object
ints object
dtype: object
指定转换的类型:
In [203]: pd.read_json('test.json', dtype={'A' : 'float32', 'bools' : 'int8'}).dtypes
Out[203]:
A float32
B float64
bools int8
date datetime64[ns]
ints int64
dtype: object
保留字符串索引:
In [204]: si = pd.DataFrame(np.zeros((4, 4)),
.....: columns=list(range(4)),
.....: index=[str(i) for i in range(4)])
.....:
In [205]: si
Out[205]:
0 1 2 3
0 0.0 0.0 0.0 0.0
1 0.0 0.0 0.0 0.0
2 0.0 0.0 0.0 0.0
3 0.0 0.0 0.0 0.0
In [206]: si.index
Out[206]: Index([u'0', u'1', u'2', u'3'], dtype='object')
In [207]: si.columns
Out[207]: Int64Index([0, 1, 2, 3], dtype='int64')
In [208]: json = si.to_json()
In [209]: sij = pd.read_json(json, convert_axes=False)
In [210]: sij
Out[210]:
0 1 2 3
0 0 0 0 0
1 0 0 0 0
2 0 0 0 0
3 0 0 0 0
In [211]: sij.index
Out[211]: Index([u'0', u'1', u'2', u'3'], dtype='object')
In [212]: sij.columns
Out[212]: Index([u'0', u'1', u'2', u'3'], dtype='object')
以纳秒为单位写入的日期需要以纳秒为单位进行读取:
In [213]: json = dfj2.to_json(date_unit='ns')
# Try to parse timestamps as millseconds -> Won't Work
In [214]: dfju = pd.read_json(json, date_unit='ms')
In [215]: dfju
Out[215]:
A B bools date ints
1356998400000000000 -1.294524 0.413738 True 1356998400000000000 0
1357084800000000000 0.276662 -0.472035 True 1356998400000000000 1
1357171200000000000 -0.013960 -0.362543 True 1356998400000000000 2
1357257600000000000 -0.006154 -0.923061 True 1356998400000000000 3
1357344000000000000 0.895717 0.805244 True 1356998400000000000 4
# Let pandas detect the correct precision
In [216]: dfju = pd.read_json(json)
In [217]: dfju
Out[217]:
A B bools date ints
2013-01-01 -1.294524 0.413738 True 2013-01-01 0
2013-01-02 0.276662 -0.472035 True 2013-01-01 1
2013-01-03 -0.013960 -0.362543 True 2013-01-01 2
2013-01-04 -0.006154 -0.923061 True 2013-01-01 3
2013-01-05 0.895717 0.805244 True 2013-01-01 4
# Or specify that all timestamps are in nanoseconds
In [218]: dfju = pd.read_json(json, date_unit='ns')
In [219]: dfju
Out[219]:
A B bools date ints
2013-01-01 -1.294524 0.413738 True 2013-01-01 0
2013-01-02 0.276662 -0.472035 True 2013-01-01 1
2013-01-03 -0.013960 -0.362543 True 2013-01-01 2
2013-01-04 -0.006154 -0.923061 True 2013-01-01 3
2013-01-05 0.895717 0.805244 True 2013-01-01 4
The Numpy Parameter¶
注意
这仅支持数值数据。索引和列标签可以是非数字的,例如。字符串,日期等。
如果numpy=True
被传递到read_json
,将尝试在反序列化期间侦听适当的dtype,然后直接解码为numpy数组,绕过对中间Python对象。
如果你反序列化大量的数值数据,这可以提供加速:
In [220]: randfloats = np.random.uniform(-100, 1000, 10000)
In [221]: randfloats.shape = (1000, 10)
In [222]: dffloats = pd.DataFrame(randfloats, columns=list('ABCDEFGHIJ'))
In [223]: jsonfloats = dffloats.to_json()
In [224]: timeit pd.read_json(jsonfloats)
100 loops, best of 3: 12.2 ms per loop
In [225]: timeit pd.read_json(jsonfloats, numpy=True)
100 loops, best of 3: 7.35 ms per loop
对于较小的数据集,加速不太明显:
In [226]: jsonfloats = dffloats.head(100).to_json()
In [227]: timeit pd.read_json(jsonfloats)
100 loops, best of 3: 5.72 ms per loop
In [228]: timeit pd.read_json(jsonfloats, numpy=True)
100 loops, best of 3: 4.94 ms per loop
警告
直接numpy解码进行了许多假设,如果不满足这些假设,可能会失败或产生意外的输出:
- 数据是数字。
- 数据是均匀的。dtype从解码的第一个值被嗅探。可能会出现
ValueError
,如果不满足此条件,可能会产生不正确的输出。- 标签是有序的。仅从第一个容器中读取标签,假定每个后续行/列都按相同的顺序进行编码。如果数据使用
to_json
编码,则应满足此要求,但如果JSON来自其他来源,则可能不是这样。
Normalization¶
版本0.13.0中的新功能。
pandas提供了一个实用函数来接受一个dict或list的列表,并将这个半结构化数据正规化到一个平面表中。
In [229]: from pandas.io.json import json_normalize
In [230]: data = [{'state': 'Florida',
.....: 'shortname': 'FL',
.....: 'info': {
.....: 'governor': 'Rick Scott'
.....: },
.....: 'counties': [{'name': 'Dade', 'population': 12345},
.....: {'name': 'Broward', 'population': 40000},
.....: {'name': 'Palm Beach', 'population': 60000}]},
.....: {'state': 'Ohio',
.....: 'shortname': 'OH',
.....: 'info': {
.....: 'governor': 'John Kasich'
.....: },
.....: 'counties': [{'name': 'Summit', 'population': 1234},
.....: {'name': 'Cuyahoga', 'population': 1337}]}]
.....:
In [231]: json_normalize(data, 'counties', ['state', 'shortname', ['info', 'governor']])
Out[231]:
name population info.governor state shortname
0 Dade 12345 Rick Scott Florida FL
1 Broward 40000 Rick Scott Florida FL
2 Palm Beach 60000 Rick Scott Florida FL
3 Summit 1234 John Kasich Ohio OH
4 Cuyahoga 1337 John Kasich Ohio OH
Line delimited json¶
版本0.19.0中的新功能。
pandas能够读取和写入使用Hadoop或Spark在数据处理管道中常见的行分隔的json文件。
In [232]: jsonl = '''
.....: {"a":1,"b":2}
.....: {"a":3,"b":4}
.....: '''
.....:
In [233]: df = pd.read_json(jsonl, lines=True)
In [234]: df
Out[234]:
a b
0 1 2
1 3 4
In [235]: df.to_json(orient='records', lines=True)
Out[235]: u'{"a":1,"b":2}\n{"a":3,"b":4}'
HTML¶
Reading HTML Content¶
警告
我们高度鼓励您阅读关于BeautifulSoup4 / html5lib / lxml解析器相关问题的HTML parsing gotchas。
版本0.12.0中的新功能。
顶层read_html()
函数可以接受HTML字符串/文件/ URL,并将HTML表解析为pandas DataFrames列表。让我们来看几个例子。
注意
read_html
返回DataFrame
对象的list
,即使HTML内容中只包含一个表
读取没有选项的网址
In [236]: url = 'http://www.fdic.gov/bank/individual/failed/banklist.html'
In [237]: dfs = pd.read_html(url)
In [238]: dfs
Out[238]:
[ Bank Name City ST CERT \
0 Allied Bank Mulberry AR 91
1 The Woodbury Banking Company Woodbury GA 11297
2 First CornerStone Bank King of Prussia PA 35312
3 Trust Company Bank Memphis TN 9956
4 North Milwaukee State Bank Milwaukee WI 20364
5 Hometown National Bank Longview WA 35156
6 The Bank of Georgia Peachtree City GA 35259
.. ... ... .. ...
540 Hamilton Bank, NA En Espanol Miami FL 24382
541 Sinclair National Bank Gravette AR 34248
542 Superior Bank, FSB Hinsdale IL 32646
543 Malta National Bank Malta OH 6629
544 First Alliance Bank & Trust Co. Manchester NH 34264
545 National State Bank of Metropolis Metropolis IL 3815
546 Bank of Honolulu Honolulu HI 21029
Acquiring Institution Closing Date \
0 Today's Bank September 23, 2016
1 United Bank August 19, 2016
2 First-Citizens Bank & Trust Company May 6, 2016
3 The Bank of Fayette County April 29, 2016
4 First-Citizens Bank & Trust Company March 11, 2016
5 Twin City Bank October 2, 2015
6 Fidelity Bank October 2, 2015
.. ... ...
540 Israel Discount Bank of New York January 11, 2002
541 Delta Trust & Bank September 7, 2001
542 Superior Federal, FSB July 27, 2001
543 North Valley Bank May 3, 2001
544 Southern New Hampshire Bank & Trust February 2, 2001
545 Banterra Bank of Marion December 14, 2000
546 Bank of the Orient October 13, 2000
Updated Date
0 November 17, 2016
1 November 17, 2016
2 September 6, 2016
3 September 6, 2016
4 June 16, 2016
5 April 13, 2016
6 October 24, 2016
.. ...
540 September 21, 2015
541 February 10, 2004
542 August 19, 2014
543 November 18, 2002
544 February 18, 2003
545 March 17, 2005
546 March 17, 2005
[547 rows x 7 columns]]
注意
来自上述URL的数据每个星期一都会更改,因此上面生成的数据和下面的数据可能会略有不同。
从上述网址读取文件的内容,并将其作为字符串传递给read_html
In [239]: with open(file_path, 'r') as f:
.....: dfs = pd.read_html(f.read())
.....:
In [240]: dfs
Out[240]:
[ Bank Name City ST CERT \
0 Banks of Wisconsin d/b/a Bank of Kenosha Kenosha WI 35386
1 Central Arizona Bank Scottsdale AZ 34527
2 Sunrise Bank Valdosta GA 58185
3 Pisgah Community Bank Asheville NC 58701
4 Douglas County Bank Douglasville GA 21649
5 Parkway Bank Lenoir NC 57158
6 Chipola Community Bank Marianna FL 58034
.. ... ... .. ...
499 Hamilton Bank, NAEn Espanol Miami FL 24382
500 Sinclair National Bank Gravette AR 34248
501 Superior Bank, FSB Hinsdale IL 32646
502 Malta National Bank Malta OH 6629
503 First Alliance Bank & Trust Co. Manchester NH 34264
504 National State Bank of Metropolis Metropolis IL 3815
505 Bank of Honolulu Honolulu HI 21029
Acquiring Institution Closing Date Updated Date
0 North Shore Bank, FSB May 31, 2013 May 31, 2013
1 Western State Bank May 14, 2013 May 20, 2013
2 Synovus Bank May 10, 2013 May 21, 2013
3 Capital Bank, N.A. May 10, 2013 May 14, 2013
4 Hamilton State Bank April 26, 2013 May 16, 2013
5 CertusBank, National Association April 26, 2013 May 17, 2013
6 First Federal Bank of Florida April 19, 2013 May 16, 2013
.. ... ... ...
499 Israel Discount Bank of New York January 11, 2002 June 5, 2012
500 Delta Trust & Bank September 7, 2001 February 10, 2004
501 Superior Federal, FSB July 27, 2001 June 5, 2012
502 North Valley Bank May 3, 2001 November 18, 2002
503 Southern New Hampshire Bank & Trust February 2, 2001 February 18, 2003
504 Banterra Bank of Marion December 14, 2000 March 17, 2005
505 Bank of the Orient October 13, 2000 March 17, 2005
[506 rows x 7 columns]]
如果你愿意,你甚至可以传递StringIO
的实例
In [241]: with open(file_path, 'r') as f:
.....: sio = StringIO(f.read())
.....:
In [242]: dfs = pd.read_html(sio)
In [243]: dfs
Out[243]:
[ Bank Name City ST CERT \
0 Banks of Wisconsin d/b/a Bank of Kenosha Kenosha WI 35386
1 Central Arizona Bank Scottsdale AZ 34527
2 Sunrise Bank Valdosta GA 58185
3 Pisgah Community Bank Asheville NC 58701
4 Douglas County Bank Douglasville GA 21649
5 Parkway Bank Lenoir NC 57158
6 Chipola Community Bank Marianna FL 58034
.. ... ... .. ...
499 Hamilton Bank, NAEn Espanol Miami FL 24382
500 Sinclair National Bank Gravette AR 34248
501 Superior Bank, FSB Hinsdale IL 32646
502 Malta National Bank Malta OH 6629
503 First Alliance Bank & Trust Co. Manchester NH 34264
504 National State Bank of Metropolis Metropolis IL 3815
505 Bank of Honolulu Honolulu HI 21029
Acquiring Institution Closing Date Updated Date
0 North Shore Bank, FSB May 31, 2013 May 31, 2013
1 Western State Bank May 14, 2013 May 20, 2013
2 Synovus Bank May 10, 2013 May 21, 2013
3 Capital Bank, N.A. May 10, 2013 May 14, 2013
4 Hamilton State Bank April 26, 2013 May 16, 2013
5 CertusBank, National Association April 26, 2013 May 17, 2013
6 First Federal Bank of Florida April 19, 2013 May 16, 2013
.. ... ... ...
499 Israel Discount Bank of New York January 11, 2002 June 5, 2012
500 Delta Trust & Bank September 7, 2001 February 10, 2004
501 Superior Federal, FSB July 27, 2001 June 5, 2012
502 North Valley Bank May 3, 2001 November 18, 2002
503 Southern New Hampshire Bank & Trust February 2, 2001 February 18, 2003
504 Banterra Bank of Marion December 14, 2000 March 17, 2005
505 Bank of the Orient October 13, 2000 March 17, 2005
[506 rows x 7 columns]]
注意
以下示例不是由IPython评估程序运行的,因为有这么多网络访问功能会减慢文档构建。如果您发现错误或无法运行的示例,请随时在pandas GitHub问题页面上报告错误。
读取网址并匹配包含特定文本的表
match = 'Metcalf Bank'
df_list = pd.read_html(url, match=match)
指定标题行(默认情况下,<th>
元素用于形成列索引);如果指定,则从数据减去经解析的报头元素(<th>
dfs = pd.read_html(url, header=0)
指定索引列
dfs = pd.read_html(url, index_col=0)
指定要跳过的行数
dfs = pd.read_html(url, skiprows=0)
使用列表指定要跳过的行数(xrange
(仅限Python 2))
dfs = pd.read_html(url, skiprows=range(2))
指定HTML属性
dfs1 = pd.read_html(url, attrs={'id': 'table'})
dfs2 = pd.read_html(url, attrs={'class': 'sortable'})
print(np.array_equal(dfs1[0], dfs2[0])) # Should be True
指定应转换为NaN的值
dfs = pd.read_html(url, na_values=['No Acquirer'])
版本0.19中的新功能。
指定是否保留默认的NaN值集
dfs = pd.read_html(url, keep_default_na=False)
版本0.19中的新功能。
指定列的转换器。这对于具有前导零的数字文本数据很有用。默认情况下,数值型的列转换为数字类型,前导零将丢失。为了避免这种情况,我们可以将这些列转换为字符串。
url_mcc = 'https://en.wikipedia.org/wiki/Mobile_country_code'
dfs = pd.read_html(url_mcc, match='Telekom Albania', header=0, converters={'MNC':
str})
版本0.19中的新功能。
使用上述的一些组合
dfs = pd.read_html(url, match='Metcalf Bank', index_col=0)
读入pandas to_html
输出(浮点精度有些损失)
df = pd.DataFrame(randn(2, 2))
s = df.to_html(float_format='{0:.40g}'.format)
dfin = pd.read_html(s, index_col=0)
The lxml
backend will raise an error on a failed parse if that is the only parser you provide (if you only have a single parser you can provide just a string, but it is considered good practice to pass a list with one string if, for example, the function expects a sequence of strings)
dfs = pd.read_html(url, 'Metcalf Bank', index_col=0, flavor=['lxml'])
要么
dfs = pd.read_html(url, 'Metcalf Bank', index_col=0, flavor='lxml')
但是,如果您安装了bs4和html5lib,并通过None
或['lxml', 'bs4'] 那么解析将很可能成功。
请注意,一旦解析成功,函数将返回。
dfs = pd.read_html(url, 'Metcalf Bank', index_col=0, flavor=['lxml', 'bs4'])
Writing to HTML files¶
DataFrame
对象具有实例方法to_html
,它将DataFrame
的内容呈现为HTML表。函数参数与上述方法to_string
中的相同。
注意
为了简洁起见,此处并未显示DataFrame.to_html
的所有可能选项。有关完整的选项集,请参见to_html()
。
In [244]: df = pd.DataFrame(randn(2, 2))
In [245]: df
Out[245]:
0 1
0 -0.184744 0.496971
1 -0.856240 1.857977
In [246]: print(df.to_html()) # raw html
<table border="1" class="dataframe">
<thead>
<tr style="text-align: right;">
<th></th>
<th>0</th>
<th>1</th>
</tr>
</thead>
<tbody>
<tr>
<th>0</th>
<td>-0.184744</td>
<td>0.496971</td>
</tr>
<tr>
<th>1</th>
<td>-0.856240</td>
<td>1.857977</td>
</tr>
</tbody>
</table>
HTML:
0 | 1 | |
---|---|---|
0 | -0.184744 | 0.496971 |
1 | -0.856240 | 1.857977 |
columns
参数将限制显示的列
In [247]: print(df.to_html(columns=[0]))
<table border="1" class="dataframe">
<thead>
<tr style="text-align: right;">
<th></th>
<th>0</th>
</tr>
</thead>
<tbody>
<tr>
<th>0</th>
<td>-0.184744</td>
</tr>
<tr>
<th>1</th>
<td>-0.856240</td>
</tr>
</tbody>
</table>
HTML:
0 | |
---|---|
0 | -0.184744 |
1 | -0.856240 |
float_format
使用Python可调用方法来控制浮点值的精度
In [248]: print(df.to_html(float_format='{0:.10f}'.format))
<table border="1" class="dataframe">
<thead>
<tr style="text-align: right;">
<th></th>
<th>0</th>
<th>1</th>
</tr>
</thead>
<tbody>
<tr>
<th>0</th>
<td>-0.1847438576</td>
<td>0.4969711327</td>
</tr>
<tr>
<th>1</th>
<td>-0.8562396763</td>
<td>1.8579766508</td>
</tr>
</tbody>
</table>
HTML:
0 | 1 | |
---|---|---|
0 | -0.1847438576 | 0.4969711327 |
1 | -0.8562396763 | 1.8579766508 |
bold_rows
会使行标签默认为粗体,但您可以关闭它
In [249]: print(df.to_html(bold_rows=False))
<table border="1" class="dataframe">
<thead>
<tr style="text-align: right;">
<th></th>
<th>0</th>
<th>1</th>
</tr>
</thead>
<tbody>
<tr>
<td>0</td>
<td>-0.184744</td>
<td>0.496971</td>
</tr>
<tr>
<td>1</td>
<td>-0.856240</td>
<td>1.857977</td>
</tr>
</tbody>
</table>
0 | 1 | |
---|---|---|
0 | -0.184744 | 0.496971 |
1 | -0.856240 | 1.857977 |
classes
参数提供了给出生成的HTML表CSS类的能力。请注意,这些类是附加到现有的'dataframe'
类。
In [250]: print(df.to_html(classes=['awesome_table_class', 'even_more_awesome_class']))
<table border="1" class="dataframe awesome_table_class even_more_awesome_class">
<thead>
<tr style="text-align: right;">
<th></th>
<th>0</th>
<th>1</th>
</tr>
</thead>
<tbody>
<tr>
<th>0</th>
<td>-0.184744</td>
<td>0.496971</td>
</tr>
<tr>
<th>1</th>
<td>-0.856240</td>
<td>1.857977</td>
</tr>
</tbody>
</table>
最后,escape
参数允许您控制在生成的HTML中转义的“”和“&”字符(默认为True
)。因此,要获取没有转义字符的HTML,请传递escape=False
In [251]: df = pd.DataFrame({'a': list('&<>'), 'b': randn(3)})
转义:
In [252]: print(df.to_html())
<table border="1" class="dataframe">
<thead>
<tr style="text-align: right;">
<th></th>
<th>a</th>
<th>b</th>
</tr>
</thead>
<tbody>
<tr>
<th>0</th>
<td>&</td>
<td>-0.474063</td>
</tr>
<tr>
<th>1</th>
<td><</td>
<td>-0.230305</td>
</tr>
<tr>
<th>2</th>
<td>></td>
<td>-0.400654</td>
</tr>
</tbody>
</table>
一个 | b | |
---|---|---|
0 | &lt; | -0.474063 |
1 | -0.230305 | |
2 | > | -0.400654 |
未逸出:
In [253]: print(df.to_html(escape=False))
<table border="1" class="dataframe">
<thead>
<tr style="text-align: right;">
<th></th>
<th>a</th>
<th>b</th>
</tr>
</thead>
<tbody>
<tr>
<th>0</th>
<td>&</td>
<td>-0.474063</td>
</tr>
<tr>
<th>1</th>
<td><</td>
<td>-0.230305</td>
</tr>
<tr>
<th>2</th>
<td>></td>
<td>-0.400654</td>
</tr>
</tbody>
</table>
一个 | b | |
---|---|---|
0 | &lt; | -0.474063 |
1 | -0.230305 | |
2 | > | -0.400654 |
注意
某些浏览器可能不会在前两个HTML表格的呈现方面显示不同。
Excel files¶
The read_excel()
method can read Excel 2003 (.xls
) and Excel 2007+ (.xlsx
) files using the xlrd
Python module. to_excel()
实例方法用于将DataFrame
保存到Excel。通常,语义与使用csv数据类似。有关某些高级策略,请参阅cookbook
Reading Excel Files¶
在最基本的用例中,read_excel
获取Excel文件的路径,sheetname
指示要解析的工作表。
# Returns a DataFrame
read_excel('path_to_file.xls', sheetname='Sheet1')
ExcelFile
class¶
为了方便使用同一文件中的多个工作表,可以使用ExcelFile
类包装文件,并将其传递到read_excel
多张纸作为文件只读入内存一次。
xlsx = pd.ExcelFile('path_to_file.xls)
df = pd.read_excel(xlsx, 'Sheet1')
ExcelFile
类也可以用作上下文管理器。
with pd.ExcelFile('path_to_file.xls') as xls:
df1 = pd.read_excel(xls, 'Sheet1')
df2 = pd.read_excel(xls, 'Sheet2')
sheet_names
属性将生成文件中的工作表名称列表。
ExcelFile
的主要用例是解析具有不同参数的多个工作表
data = {}
# For when Sheet1's format differs from Sheet2
with pd.ExcelFile('path_to_file.xls') as xls:
data['Sheet1'] = pd.read_excel(xls, 'Sheet1', index_col=None, na_values=['NA'])
data['Sheet2'] = pd.read_excel(xls, 'Sheet2', index_col=1)
请注意,如果对所有工作表使用相同的解析参数,则可以将工作表名称列表传递到read_excel
,而不会降低性能。
# using the ExcelFile class
data = {}
with pd.ExcelFile('path_to_file.xls') as xls:
data['Sheet1'] = read_excel(xls, 'Sheet1', index_col=None, na_values=['NA'])
data['Sheet2'] = read_excel(xls, 'Sheet2', index_col=None, na_values=['NA'])
# equivalent using the read_excel function
data = read_excel('path_to_file.xls', ['Sheet1', 'Sheet2'], index_col=None, na_values=['NA'])
版本0.12中的新功能。
ExcelFile
已移至顶层命名空间。
版本0.17中的新功能。
read_excel
可以使用ExcelFile
对象作为输入
Specifying Sheets¶
注意
第二个参数是sheetname
,不要与ExcelFile.sheet_names
混淆
注意
ExcelFile的属性sheet_names
提供对工作表列表的访问。
- 参数
sheetname
允许指定要读取的工作表。 sheetname
的默认值为0,表示要读取第一张工作表- 传递字符串以引用工作簿中特定工作表的名称。
- 传递整数以引用表单的索引。索引遵循Python约定,从0开始。
- 传递字符串或整数的列表,返回指定工作表的字典。
- 传递
None
可返回所有可用工作表的字典。
# Returns a DataFrame
read_excel('path_to_file.xls', 'Sheet1', index_col=None, na_values=['NA'])
使用表索引:
# Returns a DataFrame
read_excel('path_to_file.xls', 0, index_col=None, na_values=['NA'])
使用所有默认值:
# Returns a DataFrame
read_excel('path_to_file.xls')
使用无获取所有工作表:
# Returns a dictionary of DataFrames
read_excel('path_to_file.xls',sheetname=None)
使用列表获取多个工作表:
# Returns the 1st and 4th sheet, as a dictionary of DataFrames.
read_excel('path_to_file.xls',sheetname=['Sheet1',3])
版本0.16中的新功能。
read_excel
可以读取多个工作表,方法是将sheetname
设置为工作表名称列表,工作表位置列表或None
表示读取所有的表格。
版本0.13中的新功能。
可以通过工作表索引或工作表名称分别使用整数或字符串指定工作表。
Reading a MultiIndex
¶
版本0.17中的新功能。
read_excel
can read a MultiIndex
index, by passing a list of columns to index_col
and a MultiIndex
column by passing a list of rows to header
. 如果index
或columns
具有序列化的级别名称,那么通过指定组成级别的行/列,也将读入。
例如,要读取不带名称的MultiIndex
索引:
In [254]: df = pd.DataFrame({'a':[1,2,3,4], 'b':[5,6,7,8]},
.....: index=pd.MultiIndex.from_product([['a','b'],['c','d']]))
.....:
In [255]: df.to_excel('path_to_file.xlsx')
In [256]: df = pd.read_excel('path_to_file.xlsx', index_col=[0,1])
In [257]: df
Out[257]:
a b
a c 1 5
d 2 6
b c 3 7
d 4 8
如果索引具有级别名称,则它们将使用相同的参数进行解析。
In [258]: df.index = df.index.set_names(['lvl1', 'lvl2'])
In [259]: df.to_excel('path_to_file.xlsx')
In [260]: df = pd.read_excel('path_to_file.xlsx', index_col=[0,1])
In [261]: df
Out[261]:
a b
lvl1 lvl2
a c 1 5
d 2 6
b c 3 7
d 4 8
如果源文件同时具有MultiIndex
索引和列,则指定每个列的列表应传递到index_col
和header
In [262]: df.columns = pd.MultiIndex.from_product([['a'],['b', 'd']], names=['c1', 'c2'])
In [263]: df.to_excel('path_to_file.xlsx')
In [264]: df = pd.read_excel('path_to_file.xlsx',
.....: index_col=[0,1], header=[0,1])
.....:
In [265]: df
Out[265]:
c1 a
c2 b d
lvl1 lvl2
a c 1 5
d 2 6
b c 3 7
d 4 8
警告
保存在版本0.16.2或之前的具有索引名称的Excel文件仍然可以读入,但has_index_names
参数必须指定为True
。
Parsing Specific Columns¶
通常情况下,用户将插入列以在Excel中进行临时计算,并且您可能不想读取这些列。read_excel使用parse_cols关键字,以允许您指定要解析的列子集。
如果parse_cols是整数,则假定指示要解析的最后一列。
read_excel('path_to_file.xls', 'Sheet1', parse_cols=2)
如果parse_cols是整数列表,则假定它是要解析的文件列索引。
read_excel('path_to_file.xls', 'Sheet1', parse_cols=[0, 2, 3])
Cell Converters¶
可以通过转换器选项转换Excel单元格的内容。例如,要将列转换为布尔值:
read_excel('path_to_file.xls', 'Sheet1', converters={'MyBools': bool})
此选项处理缺少的值,并将转换器中的异常视为缺失数据。转换是逐个单元格应用的,而不是作为一个整体应用到列,因此不能保证数组dtype。例如,具有缺失值的整数列不能转换为具有整数dtype的数组,因为NaN严格来说是一个浮点数。您可以手动掩蔽缺少的数据以恢复整数dtype:
cfun = lambda x: int(x) if x else -1
read_excel('path_to_file.xls', 'Sheet1', converters={'MyInts': cfun})
Writing Excel Files¶
Writing Excel Files to Disk¶
要将DataFrame对象写入Excel文件的工作表,可以使用to_excel
实例方法。参数与上述的to_csv
基本相同,第一个参数是excel文件的名称,第二个参数是可选的第二个参数应该写入DataFrame的工作表的名称。例如:
df.to_excel('path_to_file.xlsx', sheet_name='Sheet1')
Files with a .xls
extension will be written using xlwt
and those with a .xlsx
extension will be written using xlsxwriter
(if available) or openpyxl
.
DataFrame将以尝试模仿REPL输出的方式写入。与0.12.0的一个区别是,index_label
将放置在第二行,而不是第一行。您可以通过将to_excel()
中的merge_cells
选项设置为False
来获取先前的行为:
df.to_excel('path_to_file.xlsx', index_label='label', merge_cells=False)
Panel类还有一个to_excel
实例方法,它将Panel中的每个DataFrame写入单独的工作表。
为了在单个Excel文件中将单独的DataFrames写入单独的工作表,可以传递ExcelWriter
。
with ExcelWriter('path_to_file.xlsx') as writer:
df1.to_excel(writer, sheet_name='Sheet1')
df2.to_excel(writer, sheet_name='Sheet2')
注意
在read_excel
在内部,Excel将所有数字数据存储为浮点数。因为这可能在读取数据时产生意想不到的行为,如果pandas不丢失信息,则默认为试图将整数转换为浮点数(1.0 - > 1
)。您可以传递convert_float=False
以禁用此行为,这可能会略微提高性能。
Writing Excel Files to Memory¶
版本0.17中的新功能。
Pandas支持使用ExcelWriter
将Excel文件写入缓冲区对象,例如StringIO
或BytesIO
。
版本0.17中的新功能。
添加了对Openpyxl> = 2.2的支持
# Safe import for either Python 2.x or 3.x
try:
from io import BytesIO
except ImportError:
from cStringIO import StringIO as BytesIO
bio = BytesIO()
# By setting the 'engine' in the ExcelWriter constructor.
writer = ExcelWriter(bio, engine='xlsxwriter')
df.to_excel(writer, sheet_name='Sheet1')
# Save the workbook
writer.save()
# Seek to the beginning and read to copy the workbook to a variable in memory
bio.seek(0)
workbook = bio.read()
注意
engine
是可选的,但建议使用。设置引擎将确定生成的工作簿的版本。设置engine='xlrd'
将生成Excel 2003格式的工作簿(xls)。使用'openpyxl'
或'xlsxwriter'
将生成Excel 2007格式的工作簿(xlsx)。如果省略,则会生成Excel 2007格式的工作簿。
Excel writer engines¶
版本0.13中的新功能。
pandas
通过两种方法选择Excel写程序:
engine
关键字参数- 文件扩展名(通过config选项中指定的默认值)
默认情况下,pandas
使用XlsxWriter表示.xlsx
和openpyxl表示.xlsm
文件和xlwt用于.xls
文件。如果您安装了多个引擎,可以通过setting the config options io.excel.xlsx.writer
和io.excel.xls.writer
。对于.xlsx
文件,如果Xlsxwriter不可用,pandas将回退到openpyxl。
要指定要使用的写入程序,可以将引擎关键字参数传递到to_excel
和ExcelWriter
。内置引擎是:
openpyxl
:这包括从1.6.1稳定支持Openpyxl。但是,建议使用版本2.2和更高版本,尤其是在使用样式时。xlsxwriter
xlwt
# By setting the 'engine' in the DataFrame and Panel 'to_excel()' methods.
df.to_excel('path_to_file.xlsx', sheet_name='Sheet1', engine='xlsxwriter')
# By setting the 'engine' in the ExcelWriter constructor.
writer = ExcelWriter('path_to_file.xlsx', engine='xlsxwriter')
# Or via pandas configuration.
from pandas import options
options.io.excel.xlsx.writer = 'xlsxwriter'
df.to_excel('path_to_file.xlsx', sheet_name='Sheet1')
Clipboard¶
抓取数据的一种方法是使用read_clipboard
方法,它将剪贴板缓冲区的内容传递给read_table
方法。例如,您可以将以下文本复制到剪贴板(在许多操作系统上为CTRL-C):
A B C
x 1 4 p
y 2 5 q
z 3 6 r
然后通过调用将数据直接导入DataFrame:
clipdf = pd.read_clipboard()
In [266]: clipdf
Out[266]:
A B C
x 1 4 p
y 2 5 q
z 3 6 r
to_clipboard
方法可用于将DataFrame的内容写入剪贴板。然后,您可以将剪贴板内容粘贴到其他应用程序(在许多操作系统上的CTRL-V)。这里我们说明将DataFrame写入剪贴板并读回。
In [267]: df = pd.DataFrame(randn(5,3))
In [268]: df
Out[268]:
0 1 2
0 -0.288267 -0.084905 0.004772
1 1.382989 0.343635 -1.253994
2 -0.124925 0.212244 0.496654
3 0.525417 1.238640 -1.210543
4 -1.175743 -0.172372 -0.734129
In [269]: df.to_clipboard()
In [270]: pd.read_clipboard()
Out[270]:
0 1 2
0 -0.288267 -0.084905 0.004772
1 1.382989 0.343635 -1.253994
2 -0.124925 0.212244 0.496654
3 0.525417 1.238640 -1.210543
4 -1.175743 -0.172372 -0.734129
我们可以看到,我们得到了相同的内容,我们以前写到剪贴板。
注意
您可能需要在Linux上安装xclip或xsel(使用gtk或PyQt4模块)来使用这些方法。
Pickling¶
所有的pandas对象都配备了使用Python的cPickle
模块使用pickle格式将数据结构保存到磁盘的to_pickle
方法。
In [271]: df
Out[271]:
0 1 2
0 -0.288267 -0.084905 0.004772
1 1.382989 0.343635 -1.253994
2 -0.124925 0.212244 0.496654
3 0.525417 1.238640 -1.210543
4 -1.175743 -0.172372 -0.734129
In [272]: df.to_pickle('foo.pkl')
pandas
命名空间中的read_pickle
函数可用于从文件加载任何腌制的pandas对象(或任何其他腌制对象)
In [273]: pd.read_pickle('foo.pkl')
Out[273]:
0 1 2
0 -0.288267 -0.084905 0.004772
1 1.382989 0.343635 -1.253994
2 -0.124925 0.212244 0.496654
3 0.525417 1.238640 -1.210543
4 -1.175743 -0.172372 -0.734129
警告
几个内部重构,0.13(Series Refactoring)和0.15(Index Refactoring)保留了与这些版本之前创建的pickles的兼容性。但是,这些必须用pd.read_pickle
读取,而不是默认的python pickle.load
。有关详细说明,请参阅此问题。
注意
这些方法以前是pd.save
和pd.load
,在0.12.0之前,现在已被弃用。
msgpack (experimental)¶
版本0.13.0中的新功能。
从0.13.0开始,pandas支持对象序列化的msgpack
格式。这是一种轻量级的便携式二进制格式,类似于二进制JSON,高度节省空间,并且在写入(串行化)和读取(反序列化)时提供良好的性能。
警告
这是熊猫的一个非常新的特点。我们打算在msgpack
数据的io中提供某些优化。由于这被标记为实验库,所以存储格式在未来版本之前可能不稳定。
由于写入格式更改和其他问题:
包装 | 可以解压缩 |
---|---|
pre-0.17 / Python 2 | 任何 |
pre-0.17 / Python 3 | 任何 |
0.17 / Python 2 |
|
0.17 / Python 3 | > = 0.18 /任何Python |
0.18 | > = 0.18 |
阅读(旧版本打包的文件)是向后兼容的,除了在Python 2中用0.17打包的文件,在这种情况下只能在Python 2中解压缩。
In [274]: df = pd.DataFrame(np.random.rand(5,2),columns=list('AB'))
In [275]: df.to_msgpack('foo.msg')
In [276]: pd.read_msgpack('foo.msg')
Out[276]:
A B
0 0.154336 0.710999
1 0.398096 0.765220
2 0.586749 0.293052
3 0.290293 0.710783
4 0.988593 0.062106
In [277]: s = pd.Series(np.random.rand(5),index=pd.date_range('20130101',periods=5))
你可以传递一个对象的列表,你会收到他们反序列化。
In [278]: pd.to_msgpack('foo.msg', df, 'foo', np.array([1,2,3]), s)
In [279]: pd.read_msgpack('foo.msg')
Out[279]:
[ A B
0 0.154336 0.710999
1 0.398096 0.765220
2 0.586749 0.293052
3 0.290293 0.710783
4 0.988593 0.062106, 'foo', array([1, 2, 3]), 2013-01-01 0.690810
2013-01-02 0.235907
2013-01-03 0.712756
2013-01-04 0.119599
2013-01-05 0.023493
Freq: D, dtype: float64]
您可以传递iterator=True
来迭代解压缩的结果
In [280]: for o in pd.read_msgpack('foo.msg',iterator=True):
.....: print o
.....:
A B
0 0.154336 0.710999
1 0.398096 0.765220
2 0.586749 0.293052
3 0.290293 0.710783
4 0.988593 0.062106
foo
[1 2 3]
2013-01-01 0.690810
2013-01-02 0.235907
2013-01-03 0.712756
2013-01-04 0.119599
2013-01-05 0.023493
Freq: D, dtype: float64
您可以将append=True
传递给编写器,以附加到现有包
In [281]: df.to_msgpack('foo.msg',append=True)
In [282]: pd.read_msgpack('foo.msg')
Out[282]:
[ A B
0 0.154336 0.710999
1 0.398096 0.765220
2 0.586749 0.293052
3 0.290293 0.710783
4 0.988593 0.062106, 'foo', array([1, 2, 3]), 2013-01-01 0.690810
2013-01-02 0.235907
2013-01-03 0.712756
2013-01-04 0.119599
2013-01-05 0.023493
Freq: D, dtype: float64, A B
0 0.154336 0.710999
1 0.398096 0.765220
2 0.586749 0.293052
3 0.290293 0.710783
4 0.988593 0.062106]
与其他io方法不同,to_msgpack
可用于每个对象基础上,df.to_msgpack()
和使用顶层pd.to_msgpack(...)
其中,您可以打包任意集合的python列表,dicts,标量,同时混合熊猫对象。
In [283]: pd.to_msgpack('foo2.msg', { 'dict' : [ { 'df' : df }, { 'string' : 'foo' }, { 'scalar' : 1. }, { 's' : s } ] })
In [284]: pd.read_msgpack('foo2.msg')
Out[284]:
{'dict': ({'df': A B
0 0.154336 0.710999
1 0.398096 0.765220
2 0.586749 0.293052
3 0.290293 0.710783
4 0.988593 0.062106},
{'string': 'foo'},
{'scalar': 1.0},
{'s': 2013-01-01 0.690810
2013-01-02 0.235907
2013-01-03 0.712756
2013-01-04 0.119599
2013-01-05 0.023493
Freq: D, dtype: float64})}
Read/Write API¶
Msgpacks也可以从字符串读取和写入字符串。
In [285]: df.to_msgpack()
Out[285]: '\x84\xa6blocks\x91\x86\xa5dtype\xa7float64\xa8compress\xc0\xa4locs\x86\xa4ndim\x01\xa5dtype\xa5int64\xa8compress\xc0\xa4data\xd8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\xa5shape\x91\x02\xa3typ\xa7ndarray\xa5shape\x92\x02\x05\xa6values\xc7P\x00\xa0\xab\xfb6H\xc1\xc3?\x98(oMgz\xd9?\x17\xaed\\\xa5\xc6\xe2?\xdc\xd0\x1bd(\x94\xd2?\xb5\xe8\xf5\x0e\x8d\xa2\xef?\x02D\xebO\x80\xc0\xe6?\x16\xbddQ\xae|\xe8?\x10?Ya[\xc1\xd2?\xa8\xfd\xcf\xa0\xbc\xbe\xe6? Z\xe1\ti\xcc\xaf?\xa5klass\xaaFloatBlock\xa4axes\x92\x86\xa4name\xc0\xa5dtype\xa6object\xa8compress\xc0\xa4data\x92\xc4\x01A\xc4\x01B\xa5klass\xa5Index\xa3typ\xa5index\x86\xa4name\xc0\xa4stop\x05\xa5start\x00\xa4step\x01\xa5klass\xaaRangeIndex\xa3typ\xabrange_index\xa3typ\xadblock_manager\xa5klass\xa9DataFrame'
此外,您可以连接字符串以生成原始对象的列表。
In [286]: pd.read_msgpack(df.to_msgpack() + s.to_msgpack())
Out[286]:
[ A B
0 0.154336 0.710999
1 0.398096 0.765220
2 0.586749 0.293052
3 0.290293 0.710783
4 0.988593 0.062106, 2013-01-01 0.690810
2013-01-02 0.235907
2013-01-03 0.712756
2013-01-04 0.119599
2013-01-05 0.023493
Freq: D, dtype: float64]
HDF5 (PyTables)¶
HDFStore
是一个类似dict的对象,使用优秀的PyTables库,使用HDF5格式能快速读取和写入pandas。有关某些高级策略,请参阅cookbook
警告
从版本0.15.0开始,pandas需要PyTables
> = 3.0.0。使用先前版本的pandas / PyTables
> = 2.3编写的存储是完全兼容的(这是以前的最小PyTables
所需的版本)。
警告
有一个PyTables
索引错误,当使用索引查询存储时可能会出现。如果您看到返回的结果子集,请升级到PyTables
> = 3.2。以前创建的商店将需要使用更新的版本重写。
警告
从版本0.17.0起,HDFStore
在默认情况下不会删除具有所有缺失值的行。以前,如果缺少所有值(索引除外),则HDFStore
将不会将这些行写入磁盘。
In [287]: store = pd.HDFStore('store.h5')
In [288]: print(store)
<class 'pandas.io.pytables.HDFStore'>
File path: store.h5
Empty
对象可以写入文件,就像将键值对添加到dict中一样:
In [289]: np.random.seed(1234)
In [290]: index = pd.date_range('1/1/2000', periods=8)
In [291]: s = pd.Series(randn(5), index=['a', 'b', 'c', 'd', 'e'])
In [292]: df = pd.DataFrame(randn(8, 3), index=index,
.....: columns=['A', 'B', 'C'])
.....:
In [293]: wp = pd.Panel(randn(2, 5, 4), items=['Item1', 'Item2'],
.....: major_axis=pd.date_range('1/1/2000', periods=5),
.....: minor_axis=['A', 'B', 'C', 'D'])
.....:
# store.put('s', s) is an equivalent method
In [294]: store['s'] = s
In [295]: store['df'] = df
In [296]: store['wp'] = wp
# the type of stored data
In [297]: store.root.wp._v_attrs.pandas_type
Out[297]: 'wide'
In [298]: store
Out[298]:
<class 'pandas.io.pytables.HDFStore'>
File path: store.h5
/df frame (shape->[8,3])
/s series (shape->[5])
/wp wide (shape->[2,5,4])
在当前或以后的Python会话中,您可以检索存储的对象:
# store.get('df') is an equivalent method
In [299]: store['df']
Out[299]:
A B C
2000-01-01 0.887163 0.859588 -0.636524
2000-01-02 0.015696 -2.242685 1.150036
2000-01-03 0.991946 0.953324 -2.021255
2000-01-04 -0.334077 0.002118 0.405453
2000-01-05 0.289092 1.321158 -1.546906
2000-01-06 -0.202646 -0.655969 0.193421
2000-01-07 0.553439 1.318152 -0.469305
2000-01-08 0.675554 -1.817027 -0.183109
# dotted (attribute) access provides get as well
In [300]: store.df
Out[300]:
A B C
2000-01-01 0.887163 0.859588 -0.636524
2000-01-02 0.015696 -2.242685 1.150036
2000-01-03 0.991946 0.953324 -2.021255
2000-01-04 -0.334077 0.002118 0.405453
2000-01-05 0.289092 1.321158 -1.546906
2000-01-06 -0.202646 -0.655969 0.193421
2000-01-07 0.553439 1.318152 -0.469305
2000-01-08 0.675554 -1.817027 -0.183109
删除由键指定的对象
# store.remove('wp') is an equivalent method
In [301]: del store['wp']
In [302]: store
Out[302]:
<class 'pandas.io.pytables.HDFStore'>
File path: store.h5
/df frame (shape->[8,3])
/s series (shape->[5])
关闭store对象,上下文管理器
In [303]: store.close()
In [304]: store
Out[304]:
<class 'pandas.io.pytables.HDFStore'>
File path: store.h5
File is CLOSED
In [305]: store.is_open
Out[305]: False
# Working with, and automatically closing the store with the context
# manager
In [306]: with pd.HDFStore('store.h5') as store:
.....: store.keys()
.....:
Read/Write API¶
HDFStore
supports an top-level API using read_hdf
for reading and to_hdf
for writing, similar to how read_csv
and to_csv
work. (新的0.11.0)
In [307]: df_tl = pd.DataFrame(dict(A=list(range(5)), B=list(range(5))))
In [308]: df_tl.to_hdf('store_tl.h5','table',append=True)
In [309]: pd.read_hdf('store_tl.h5', 'table', where = ['index>2'])
Out[309]:
A B
3 3 3
4 4 4
从0.17.0版本开始,HDFStore将不再删除默认情况下都缺失的行。可以通过设置dropna=True
来启用此行为。
In [310]: df_with_missing = pd.DataFrame({'col1':[0, np.nan, 2],
.....: 'col2':[1, np.nan, np.nan]})
.....:
In [311]: df_with_missing
Out[311]:
col1 col2
0 0.0 1.0
1 NaN NaN
2 2.0 NaN
In [312]: df_with_missing.to_hdf('file.h5', 'df_with_missing',
.....: format = 'table', mode='w')
.....:
In [313]: pd.read_hdf('file.h5', 'df_with_missing')
Out[313]:
col1 col2
0 0.0 1.0
1 NaN NaN
2 2.0 NaN
In [314]: df_with_missing.to_hdf('file.h5', 'df_with_missing',
.....: format = 'table', mode='w', dropna=True)
.....:
In [315]: pd.read_hdf('file.h5', 'df_with_missing')
Out[315]:
col1 col2
0 0.0 1.0
2 2.0 NaN
对于Panel
的长轴也是如此:
In [316]: matrix = [[[np.nan, np.nan, np.nan],[1,np.nan,np.nan]],
.....: [[np.nan, np.nan, np.nan], [np.nan,5,6]],
.....: [[np.nan, np.nan, np.nan],[np.nan,3,np.nan]]]
.....:
In [317]: panel_with_major_axis_all_missing = pd.Panel(matrix,
.....: items=['Item1', 'Item2','Item3'],
.....: major_axis=[1,2],
.....: minor_axis=['A', 'B', 'C'])
.....:
In [318]: panel_with_major_axis_all_missing
Out[318]:
<class 'pandas.core.panel.Panel'>
Dimensions: 3 (items) x 2 (major_axis) x 3 (minor_axis)
Items axis: Item1 to Item3
Major_axis axis: 1 to 2
Minor_axis axis: A to C
In [319]: panel_with_major_axis_all_missing.to_hdf('file.h5', 'panel',
.....: dropna = True,
.....: format='table',
.....: mode='w')
.....:
In [320]: reloaded = pd.read_hdf('file.h5', 'panel')
In [321]: reloaded
Out[321]:
<class 'pandas.core.panel.Panel'>
Dimensions: 3 (items) x 1 (major_axis) x 3 (minor_axis)
Items axis: Item1 to Item3
Major_axis axis: 2 to 2
Minor_axis axis: A to C
Fixed Format¶
注意
这是Storer
格式之前的0.13.0。
以上示例显示使用put
进行存储,其以固定阵列格式(称为fixed
格式)将HDF5写入PyTables
。这些类型的存储是不是可写的一次写入(虽然你可以简单地删除它们和重写)。它们也不是可查询的;它们必须全部检索。它们也不支持具有非唯一列名的数据帧。fixed
格式存储提供非常快的写入和稍微快于table
存储的读取。当使用put
或to_hdf
或format='fixed'
或format='f'
警告
如果您尝试使用where
检索,则fixed
格式将产生TypeError
。
pd.DataFrame(randn(10,2)).to_hdf('test_fixed.h5','df')
pd.read_hdf('test_fixed.h5','df',where='index>5')
TypeError: cannot pass a where specification when reading a fixed format.
this store must be selected in its entirety
Table Format¶
HDFStore
支持磁盘上的另一个PyTables
格式,table
格式。概念上,table
的形状非常像DataFrame,具有行和列。可以在相同会话或其他会话中附加table
。此外,支持删除和查询类型操作。This format is specified by format='table'
or format='t'
to append
or put
or to_hdf
版本0.13中的新功能。
此格式可以设置为默认情况下启用put/append/to_hdf
的选项pd.set_option('io.hdf.default_format','table')
以table
格式保存。
In [322]: store = pd.HDFStore('store.h5')
In [323]: df1 = df[0:4]
In [324]: df2 = df[4:]
# append data (creates a table automatically)
In [325]: store.append('df', df1)
In [326]: store.append('df', df2)
In [327]: store
Out[327]:
<class 'pandas.io.pytables.HDFStore'>
File path: store.h5
/df frame_table (typ->appendable,nrows->8,ncols->3,indexers->[index])
# select the entire object
In [328]: store.select('df')
Out[328]:
A B C
2000-01-01 0.887163 0.859588 -0.636524
2000-01-02 0.015696 -2.242685 1.150036
2000-01-03 0.991946 0.953324 -2.021255
2000-01-04 -0.334077 0.002118 0.405453
2000-01-05 0.289092 1.321158 -1.546906
2000-01-06 -0.202646 -0.655969 0.193421
2000-01-07 0.553439 1.318152 -0.469305
2000-01-08 0.675554 -1.817027 -0.183109
# the type of stored data
In [329]: store.root.df._v_attrs.pandas_type
Out[329]: 'frame_table'
注意
您还可以通过将format='table'
或format='t'
传递到put
来创建table
Hierarchical Keys¶
商店的键可以指定为字符串。这些可以是层次化路径名格式(例如foo/bar/bah
),它将生成子存储的层次结构(或PyTables中的Groups
) 。键可以指定前面的'/',并且是绝对的(例如'foo'是指'/ foo')。删除操作可以删除子存储和BELOW中的所有内容,因此请小心。
In [330]: store.put('foo/bar/bah', df)
In [331]: store.append('food/orange', df)
In [332]: store.append('food/apple', df)
In [333]: store
Out[333]:
<class 'pandas.io.pytables.HDFStore'>
File path: store.h5
/df frame_table (typ->appendable,nrows->8,ncols->3,indexers->[index])
/foo/bar/bah frame (shape->[8,3])
/food/apple frame_table (typ->appendable,nrows->8,ncols->3,indexers->[index])
/food/orange frame_table (typ->appendable,nrows->8,ncols->3,indexers->[index])
# a list of keys are returned
In [334]: store.keys()
Out[334]: ['/df', '/food/apple', '/food/orange', '/foo/bar/bah']
# remove all nodes under this level
In [335]: store.remove('food')
In [336]: store
Out[336]:
<class 'pandas.io.pytables.HDFStore'>
File path: store.h5
/df frame_table (typ->appendable,nrows->8,ncols->3,indexers->[index])
/foo/bar/bah frame (shape->[8,3])
警告
分层密钥不能被检索为如上所述的存储在根节点下的项目的点(属性)访问。
In [8]: store.foo.bar.bah
AttributeError: 'HDFStore' object has no attribute 'foo'
# you can directly access the actual PyTables node but using the root node
In [9]: store.root.foo.bar.bah
Out[9]:
/foo/bar/bah (Group) ''
children := ['block0_items' (Array), 'block0_values' (Array), 'axis0' (Array), 'axis1' (Array)]
相反,使用显式字符串为基础的键
In [337]: store['foo/bar/bah']
Out[337]:
A B C
2000-01-01 0.887163 0.859588 -0.636524
2000-01-02 0.015696 -2.242685 1.150036
2000-01-03 0.991946 0.953324 -2.021255
2000-01-04 -0.334077 0.002118 0.405453
2000-01-05 0.289092 1.321158 -1.546906
2000-01-06 -0.202646 -0.655969 0.193421
2000-01-07 0.553439 1.318152 -0.469305
2000-01-08 0.675554 -1.817027 -0.183109
Storing Types¶
Storing Mixed Types in a Table¶
支持存储混合数据类型。字符串使用附加列的最大大小存储为固定宽度。随后尝试追加更长的字符串将产生ValueError
。
将min_itemsize = {`values`: size}
作为参数传递将为字符串列设置较大的最小值。存储浮点, 字符串, int, bools, datetime64 t0>目前支持。
对于字符串列,传递nan_rep = 'nan'
可以更改磁盘上的默认nan表示转换为/从np.nan),默认为nan。
In [338]: df_mixed = pd.DataFrame({ 'A' : randn(8),
.....: 'B' : randn(8),
.....: 'C' : np.array(randn(8),dtype='float32'),
.....: 'string' :'string',
.....: 'int' : 1,
.....: 'bool' : True,
.....: 'datetime64' : pd.Timestamp('20010102')},
.....: index=list(range(8)))
.....:
In [339]: df_mixed.ix[3:5,['A', 'B', 'string', 'datetime64']] = np.nan
In [340]: store.append('df_mixed', df_mixed, min_itemsize = {'values': 50})
In [341]: df_mixed1 = store.select('df_mixed')
In [342]: df_mixed1
Out[342]:
A B C bool datetime64 int string
0 0.704721 -1.152659 -0.430096 True 2001-01-02 1 string
1 -0.785435 0.631979 0.767369 True 2001-01-02 1 string
2 0.462060 0.039513 0.984920 True 2001-01-02 1 string
3 NaN NaN 0.270836 True NaT 1 NaN
4 NaN NaN 1.391986 True NaT 1 NaN
5 NaN NaN 0.079842 True NaT 1 NaN
6 2.007843 0.152631 -0.399965 True 2001-01-02 1 string
7 0.226963 0.164530 -1.027851 True 2001-01-02 1 string
In [343]: df_mixed1.get_dtype_counts()
Out[343]:
bool 1
datetime64[ns] 1
float32 1
float64 2
int64 1
object 1
dtype: int64
# we have provided a minimum string column size
In [344]: store.root.df_mixed.table
Out[344]:
/df_mixed/table (Table(8,)) ''
description := {
"index": Int64Col(shape=(), dflt=0, pos=0),
"values_block_0": Float64Col(shape=(2,), dflt=0.0, pos=1),
"values_block_1": Float32Col(shape=(1,), dflt=0.0, pos=2),
"values_block_2": Int64Col(shape=(1,), dflt=0, pos=3),
"values_block_3": Int64Col(shape=(1,), dflt=0, pos=4),
"values_block_4": BoolCol(shape=(1,), dflt=False, pos=5),
"values_block_5": StringCol(itemsize=50, shape=(1,), dflt='', pos=6)}
byteorder := 'little'
chunkshape := (689,)
autoindex := True
colindexes := {
"index": Index(6, medium, shuffle, zlib(1)).is_csi=False}
Storing Multi-Index DataFrames¶
将多索引数据帧存储为表非常类似于从同构索引DataFrames存储/选择。
In [345]: index = pd.MultiIndex(levels=[['foo', 'bar', 'baz', 'qux'],
.....: ['one', 'two', 'three']],
.....: labels=[[0, 0, 0, 1, 1, 2, 2, 3, 3, 3],
.....: [0, 1, 2, 0, 1, 1, 2, 0, 1, 2]],
.....: names=['foo', 'bar'])
.....:
In [346]: df_mi = pd.DataFrame(np.random.randn(10, 3), index=index,
.....: columns=['A', 'B', 'C'])
.....:
In [347]: df_mi
Out[347]:
A B C
foo bar
foo one -0.584718 0.816594 -0.081947
two -0.344766 0.528288 -1.068989
three -0.511881 0.291205 0.566534
bar one 0.503592 0.285296 0.484288
two 1.363482 -0.781105 -0.468018
baz two 1.224574 -1.281108 0.875476
three -1.710715 -0.450765 0.749164
qux one -0.203933 -0.182175 0.680656
two -1.818499 0.047072 0.394844
three -0.248432 -0.617707 -0.682884
In [348]: store.append('df_mi',df_mi)
In [349]: store.select('df_mi')
Out[349]:
A B C
foo bar
foo one -0.584718 0.816594 -0.081947
two -0.344766 0.528288 -1.068989
three -0.511881 0.291205 0.566534
bar one 0.503592 0.285296 0.484288
two 1.363482 -0.781105 -0.468018
baz two 1.224574 -1.281108 0.875476
three -1.710715 -0.450765 0.749164
qux one -0.203933 -0.182175 0.680656
two -1.818499 0.047072 0.394844
three -0.248432 -0.617707 -0.682884
# the levels are automatically included as data columns
In [350]: store.select('df_mi', 'foo=bar')
Out[350]:
A B C
foo bar
bar one 0.503592 0.285296 0.484288
two 1.363482 -0.781105 -0.468018
Querying¶
Querying a Table¶
警告
此查询功能在0.13.0
中实质性更改。如果其不是字符串类型,则接受来自先前版本的查询(使用DeprecationWarning
)。
select
和delete
操作具有可选择的标准,可以指定仅选择/删除数据的子集。这允许有一个非常大的磁盘表,并且只检索一部分数据。
使用Term
类指定查询作为布尔表达式。
index
和columns
是DataFrame的支持索引器major_axis
,minor_axis
和items
是面板的支持索引器- 如果指定
data_columns
,这些可以用作附加索引器
有效的比较运算符为:
=, ==, !=, &gt;, / t5> &lt;, &lt; =
有效的布尔表达式结合:
|
:或&
:和(
and)
:用于分组
这些规则类似于在pandas中用于索引的布尔表达式。
注意
=
将自动展开为比较运算符==
~
是非运算符,但只能在非常有限的情况下使用- 如果传递表达式的列表/元组,则它们将通过
&
组合
以下是有效的表达式:
'index>=date'
“columns = ['A', 'D']”
"columns in ['A', 'D']"
'columns=A'
'columns==A'
"~(columns=['A','B'])"
'index&gt; df.index [3] &amp; string =“bar”'
'(索引&gt; df.index [3] &amp; 索引 string =“bar”'
"ts>=Timestamp('2012-02-01')"
"major_axis>=20130101"
indexers
位于子表达式的左侧:
columns
,major_axis
,ts
子表达式的右侧(在比较运算符之后)可以是:
- 将被评估的函数,例如。
Timestamp('2012-02-01')
- 字符串,例如
"bar"
- 日期样。
20130101
或"20130101"
- 列表,例如。
"['A','B']"
- 在本地名称空间中定义的变量,例如。
date
注意
不推荐通过将字符串插入查询表达式来将字符串传递给查询。只需将感兴趣的字符串分配给变量,并在表达式中使用该变量。例如,这样做
string = "HolyMoly'"
store.select('df', 'index == string')
而不是这个
string = "HolyMoly'"
store.select('df', 'index == %s' % string)
后者将不工作,并会引发SyntaxError
。注意,在string
变量中有一个单引号后跟一个双引号。
如果必须插值,请使用'%r'
格式说明符
store.select('df', 'index == %r' % string)
其将引用string
。
这里有些例子:
In [351]: dfq = pd.DataFrame(randn(10,4),columns=list('ABCD'),index=pd.date_range('20130101',periods=10))
In [352]: store.append('dfq',dfq,format='table',data_columns=True)
使用布尔表达式,具有行内函数评估。
In [353]: store.select('dfq',"index>pd.Timestamp('20130104') & columns=['A', 'B']")
Out[353]:
A B
2013-01-05 1.210384 0.797435
2013-01-06 -0.850346 1.176812
2013-01-07 0.984188 -0.121728
2013-01-08 0.796595 -0.474021
2013-01-09 -0.804834 -2.123620
2013-01-10 0.334198 0.536784
使用和内联列引用
In [354]: store.select('dfq',where="A>0 or C>0")
Out[354]:
A B C D
2013-01-01 0.436258 -1.703013 0.393711 -0.479324
2013-01-02 -0.299016 0.694103 0.678630 0.239556
2013-01-03 0.151227 0.816127 1.893534 0.639633
2013-01-04 -0.962029 -2.085266 1.930247 -1.735349
2013-01-05 1.210384 0.797435 -0.379811 0.702562
2013-01-07 0.984188 -0.121728 2.365769 0.496143
2013-01-08 0.796595 -0.474021 -0.056696 1.357797
2013-01-10 0.334198 0.536784 -0.743830 -0.320204
也与小组一起工作。
In [355]: store.append('wp',wp)
In [356]: store
Out[356]:
<class 'pandas.io.pytables.HDFStore'>
File path: store.h5
/df frame_table (typ->appendable,nrows->8,ncols->3,indexers->[index])
/df_mi frame_table (typ->appendable_multi,nrows->10,ncols->5,indexers->[index],dc->[bar,foo])
/df_mixed frame_table (typ->appendable,nrows->8,ncols->7,indexers->[index])
/dfq frame_table (typ->appendable,nrows->10,ncols->4,indexers->[index],dc->[A,B,C,D])
/foo/bar/bah frame (shape->[8,3])
/wp wide_table (typ->appendable,nrows->20,ncols->2,indexers->[major_axis,minor_axis])
In [357]: store.select('wp', "major_axis>pd.Timestamp('20000102') & minor_axis=['A', 'B']")
Out[357]:
<class 'pandas.core.panel.Panel'>
Dimensions: 2 (items) x 3 (major_axis) x 2 (minor_axis)
Items axis: Item1 to Item2
Major_axis axis: 2000-01-03 00:00:00 to 2000-01-05 00:00:00
Minor_axis axis: A to B
可以提供columns
关键字来选择要返回的列的列表,这相当于传递'columns=list_of_columns_to_filter'
:
In [358]: store.select('df', "columns=['A', 'B']")
Out[358]:
A B
2000-01-01 0.887163 0.859588
2000-01-02 0.015696 -2.242685
2000-01-03 0.991946 0.953324
2000-01-04 -0.334077 0.002118
2000-01-05 0.289092 1.321158
2000-01-06 -0.202646 -0.655969
2000-01-07 0.553439 1.318152
2000-01-08 0.675554 -1.817027
可以指定start
和stop
参数来限制总搜索空间。这些是根据表中的总行数。
# this is effectively what the storage of a Panel looks like
In [359]: wp.to_frame()
Out[359]:
Item1 Item2
major minor
2000-01-01 A 1.058969 0.215269
B -0.397840 0.841009
C 0.337438 -1.445810
D 1.047579 -1.401973
2000-01-02 A 1.045938 -0.100918
B 0.863717 -0.548242
C -0.122092 -0.144620
... ... ...
2000-01-04 B 0.036142 0.307969
C -2.074978 -0.208499
D 0.247792 1.033801
2000-01-05 A -0.897157 -2.400454
B -0.136795 2.030604
C 0.018289 -1.142631
D 0.755414 0.211883
[20 rows x 2 columns]
# limiting the search
In [360]: store.select('wp',"major_axis>20000102 & minor_axis=['A','B']",
.....: start=0, stop=10)
.....:
Out[360]:
<class 'pandas.core.panel.Panel'>
Dimensions: 2 (items) x 1 (major_axis) x 2 (minor_axis)
Items axis: Item1 to Item2
Major_axis axis: 2000-01-03 00:00:00 to 2000-01-03 00:00:00
Minor_axis axis: A to B
注意
如果查询表达式具有未知的变量引用,则select
将引发ValueError
。通常这意味着您试图在而不是数据列的列上选择。
如果查询表达式无效,则select
会引发SyntaxError
。
Using timedelta64[ns]¶
版本0.13中的新功能。
从0.13.0开始,您可以使用timedelta64[ns]
类型存储和查询。Terms can be specified in the format: <float>(<unit>)
, where float may be signed (and fractional), and unit can be D,s,ms,us,ns
for the timedelta. 这里有一个例子:
In [361]: from datetime import timedelta
In [362]: dftd = pd.DataFrame(dict(A = pd.Timestamp('20130101'), B = [ pd.Timestamp('20130101') + timedelta(days=i,seconds=10) for i in range(10) ]))
In [363]: dftd['C'] = dftd['A']-dftd['B']
In [364]: dftd
Out[364]:
A B C
0 2013-01-01 2013-01-01 00:00:10 -1 days +23:59:50
1 2013-01-01 2013-01-02 00:00:10 -2 days +23:59:50
2 2013-01-01 2013-01-03 00:00:10 -3 days +23:59:50
3 2013-01-01 2013-01-04 00:00:10 -4 days +23:59:50
4 2013-01-01 2013-01-05 00:00:10 -5 days +23:59:50
5 2013-01-01 2013-01-06 00:00:10 -6 days +23:59:50
6 2013-01-01 2013-01-07 00:00:10 -7 days +23:59:50
7 2013-01-01 2013-01-08 00:00:10 -8 days +23:59:50
8 2013-01-01 2013-01-09 00:00:10 -9 days +23:59:50
9 2013-01-01 2013-01-10 00:00:10 -10 days +23:59:50
In [365]: store.append('dftd',dftd,data_columns=True)
In [366]: store.select('dftd',"C<'-3.5D'")
Out[366]:
A B C
4 2013-01-01 2013-01-05 00:00:10 -5 days +23:59:50
5 2013-01-01 2013-01-06 00:00:10 -6 days +23:59:50
6 2013-01-01 2013-01-07 00:00:10 -7 days +23:59:50
7 2013-01-01 2013-01-08 00:00:10 -8 days +23:59:50
8 2013-01-01 2013-01-09 00:00:10 -9 days +23:59:50
9 2013-01-01 2013-01-10 00:00:10 -10 days +23:59:50
Indexing¶
在数据已经在表中之后(在append/put
操作之后),可以使用create_table_index
创建/修改表的索引。鼓励创建表索引高度。当您使用索引维度作为where
的select
时,这将加快查询速度。
注意
在索引表和您指定的任何数据列上自动创建索引(起始0.10.1
)。可以通过将index=False
传递给append
来关闭此行为。
# we have automagically already created an index (in the first section)
In [367]: i = store.root.df.table.cols.index.index
In [368]: i.optlevel, i.kind
Out[368]: (6, 'medium')
# change an index by passing new parameters
In [369]: store.create_table_index('df', optlevel=9, kind='full')
In [370]: i = store.root.df.table.cols.index.index
In [371]: i.optlevel, i.kind
Out[371]: (9, 'full')
通常当将大量数据附加到内存时,关闭每个附加项的索引创建是有用的,然后在结束时重新创建。
In [372]: df_1 = pd.DataFrame(randn(10,2),columns=list('AB'))
In [373]: df_2 = pd.DataFrame(randn(10,2),columns=list('AB'))
In [374]: st = pd.HDFStore('appends.h5',mode='w')
In [375]: st.append('df', df_1, data_columns=['B'], index=False)
In [376]: st.append('df', df_2, data_columns=['B'], index=False)
In [377]: st.get_storer('df').table
Out[377]:
/df/table (Table(20,)) ''
description := {
"index": Int64Col(shape=(), dflt=0, pos=0),
"values_block_0": Float64Col(shape=(1,), dflt=0.0, pos=1),
"B": Float64Col(shape=(), dflt=0.0, pos=2)}
byteorder := 'little'
chunkshape := (2730,)
然后在完成附加时创建索引。
In [378]: st.create_table_index('df', columns=['B'], optlevel=9, kind='full')
In [379]: st.get_storer('df').table
Out[379]:
/df/table (Table(20,)) ''
description := {
"index": Int64Col(shape=(), dflt=0, pos=0),
"values_block_0": Float64Col(shape=(1,), dflt=0.0, pos=1),
"B": Float64Col(shape=(), dflt=0.0, pos=2)}
byteorder := 'little'
chunkshape := (2730,)
autoindex := True
colindexes := {
"B": Index(9, full, shuffle, zlib(1)).is_csi=True}
In [380]: st.close()
有关如何在现有存储上创建完全排序索引(CSI)的信息,请参见此处。
Query via Data Columns¶
您可以指定(和建立索引)您希望能够执行查询的某些列(除了可以始终查询的可索引的列)。例如,您想要执行此常见操作,磁盘上,并只返回匹配此查询的框架。您可以指定data_columns = True
以强制所有列为data_columns
In [381]: df_dc = df.copy()
In [382]: df_dc['string'] = 'foo'
In [383]: df_dc.ix[4:6,'string'] = np.nan
In [384]: df_dc.ix[7:9,'string'] = 'bar'
In [385]: df_dc['string2'] = 'cool'
In [386]: df_dc.ix[1:3,['B','C']] = 1.0
In [387]: df_dc
Out[387]:
A B C string string2
2000-01-01 0.887163 0.859588 -0.636524 foo cool
2000-01-02 0.015696 1.000000 1.000000 foo cool
2000-01-03 0.991946 1.000000 1.000000 foo cool
2000-01-04 -0.334077 0.002118 0.405453 foo cool
2000-01-05 0.289092 1.321158 -1.546906 NaN cool
2000-01-06 -0.202646 -0.655969 0.193421 NaN cool
2000-01-07 0.553439 1.318152 -0.469305 foo cool
2000-01-08 0.675554 -1.817027 -0.183109 bar cool
# on-disk operations
In [388]: store.append('df_dc', df_dc, data_columns = ['B', 'C', 'string', 'string2'])
In [389]: store.select('df_dc', [ pd.Term('B>0') ])
Out[389]:
A B C string string2
2000-01-01 0.887163 0.859588 -0.636524 foo cool
2000-01-02 0.015696 1.000000 1.000000 foo cool
2000-01-03 0.991946 1.000000 1.000000 foo cool
2000-01-04 -0.334077 0.002118 0.405453 foo cool
2000-01-05 0.289092 1.321158 -1.546906 NaN cool
2000-01-07 0.553439 1.318152 -0.469305 foo cool
# getting creative
In [390]: store.select('df_dc', 'B > 0 & C > 0 & string == foo')
Out[390]:
A B C string string2
2000-01-02 0.015696 1.000000 1.000000 foo cool
2000-01-03 0.991946 1.000000 1.000000 foo cool
2000-01-04 -0.334077 0.002118 0.405453 foo cool
# this is in-memory version of this type of selection
In [391]: df_dc[(df_dc.B > 0) & (df_dc.C > 0) & (df_dc.string == 'foo')]
Out[391]:
A B C string string2
2000-01-02 0.015696 1.000000 1.000000 foo cool
2000-01-03 0.991946 1.000000 1.000000 foo cool
2000-01-04 -0.334077 0.002118 0.405453 foo cool
# we have automagically created this index and the B/C/string/string2
# columns are stored separately as ``PyTables`` columns
In [392]: store.root.df_dc.table
Out[392]:
/df_dc/table (Table(8,)) ''
description := {
"index": Int64Col(shape=(), dflt=0, pos=0),
"values_block_0": Float64Col(shape=(1,), dflt=0.0, pos=1),
"B": Float64Col(shape=(), dflt=0.0, pos=2),
"C": Float64Col(shape=(), dflt=0.0, pos=3),
"string": StringCol(itemsize=3, shape=(), dflt='', pos=4),
"string2": StringCol(itemsize=4, shape=(), dflt='', pos=5)}
byteorder := 'little'
chunkshape := (1680,)
autoindex := True
colindexes := {
"index": Index(6, medium, shuffle, zlib(1)).is_csi=False,
"C": Index(6, medium, shuffle, zlib(1)).is_csi=False,
"B": Index(6, medium, shuffle, zlib(1)).is_csi=False,
"string2": Index(6, medium, shuffle, zlib(1)).is_csi=False,
"string": Index(6, medium, shuffle, zlib(1)).is_csi=False}
通过将大量列置入数据列中,会有一些性能下降,因此由用户指定这些列。此外,你不能在第一次append / put操作后更改数据列(也不能索引)(当然你可以简单地读入数据并创建一个新表!)
Iterator¶
从0.11.0
开始,您可以传递iterator=True
或chunksize=number_in_a_chunk
到select
和select_as_multiple
在结果上返回一个迭代器。默认值是在一个块中返回的50,000行。
In [393]: for df in store.select('df', chunksize=3):
.....: print(df)
.....:
A B C
2000-01-01 0.887163 0.859588 -0.636524
2000-01-02 0.015696 -2.242685 1.150036
2000-01-03 0.991946 0.953324 -2.021255
A B C
2000-01-04 -0.334077 0.002118 0.405453
2000-01-05 0.289092 1.321158 -1.546906
2000-01-06 -0.202646 -0.655969 0.193421
A B C
2000-01-07 0.553439 1.318152 -0.469305
2000-01-08 0.675554 -1.817027 -0.183109
注意
版本0.12.0中的新功能。
您还可以使用具有read_hdf
的迭代器,它将打开,然后在完成迭代后自动关闭存储。
for df in pd.read_hdf('store.h5','df', chunksize=3):
print(df)
请注意,chunksize关键字适用于源行。因此,如果您正在执行查询,那么chunksize将细分表中的所有行并应用查询,在可能不等大小的块上返回一个迭代器。
下面是一个生成查询并使用它来创建大小相等的返回块的方法。
In [394]: dfeq = pd.DataFrame({'number': np.arange(1,11)})
In [395]: dfeq
Out[395]:
number
0 1
1 2
2 3
3 4
4 5
5 6
6 7
7 8
8 9
9 10
In [396]: store.append('dfeq', dfeq, data_columns=['number'])
In [397]: def chunks(l, n):
.....: return [l[i:i+n] for i in range(0, len(l), n)]
.....:
In [398]: evens = [2,4,6,8,10]
In [399]: coordinates = store.select_as_coordinates('dfeq','number=evens')
In [400]: for c in chunks(coordinates, 2):
.....: print store.select('dfeq',where=c)
.....:
number
1 2
3 4
number
5 6
7 8
number
9 10
Advanced Queries¶
Select a Single Column¶
要检索单个可索引或数据列,请使用方法select_column
。例如,这将使您能够非常快地获取索引。这些返回结果的Series
,由行号索引。它们目前不接受where
选择器。
In [401]: store.select_column('df_dc', 'index')
Out[401]:
0 2000-01-01
1 2000-01-02
2 2000-01-03
3 2000-01-04
4 2000-01-05
5 2000-01-06
6 2000-01-07
7 2000-01-08
Name: index, dtype: datetime64[ns]
In [402]: store.select_column('df_dc', 'string')
Out[402]:
0 foo
1 foo
2 foo
3 foo
4 NaN
5 NaN
6 foo
7 bar
Name: string, dtype: object
Selecting coordinates¶
有时您想要获取查询的坐标(a.k.a索引位置)。这将返回结果位置的Int64Index
。这些坐标也可以传递到后续的where
操作。
In [403]: df_coord = pd.DataFrame(np.random.randn(1000,2),index=pd.date_range('20000101',periods=1000))
In [404]: store.append('df_coord',df_coord)
In [405]: c = store.select_as_coordinates('df_coord','index>20020101')
In [406]: c.summary()
Out[406]: u'Int64Index: 268 entries, 732 to 999'
In [407]: store.select('df_coord',where=c)
Out[407]:
0 1
2002-01-02 -0.178266 -0.064638
2002-01-03 -1.204956 -3.880898
2002-01-04 0.974470 0.415160
2002-01-05 1.751967 0.485011
2002-01-06 -0.170894 0.748870
2002-01-07 0.629793 0.811053
2002-01-08 2.133776 0.238459
... ... ...
2002-09-20 -0.181434 0.612399
2002-09-21 -0.763324 -0.354962
2002-09-22 -0.261776 0.812126
2002-09-23 0.482615 -0.886512
2002-09-24 -0.037757 -0.562953
2002-09-25 0.897706 0.383232
2002-09-26 -1.324806 1.139269
[268 rows x 2 columns]
Selecting using a where mask¶
有时,您的查询可能涉及创建要选择的行的列表。通常,此mask
将是来自索引操作的结果index
。此示例选择datetimeindex的月份为5。
In [408]: df_mask = pd.DataFrame(np.random.randn(1000,2),index=pd.date_range('20000101',periods=1000))
In [409]: store.append('df_mask',df_mask)
In [410]: c = store.select_column('df_mask','index')
In [411]: where = c[pd.DatetimeIndex(c).month==5].index
In [412]: store.select('df_mask',where=where)
Out[412]:
0 1
2000-05-01 -1.006245 -0.616759
2000-05-02 0.218940 0.717838
2000-05-03 0.013333 1.348060
2000-05-04 0.662176 -1.050645
2000-05-05 -1.034870 -0.243242
2000-05-06 -0.753366 -1.454329
2000-05-07 -1.022920 -0.476989
... ... ...
2002-05-25 -0.509090 -0.389376
2002-05-26 0.150674 1.164337
2002-05-27 -0.332944 0.115181
2002-05-28 -1.048127 -0.605733
2002-05-29 1.418754 -0.442835
2002-05-30 -0.433200 0.835001
2002-05-31 -1.041278 1.401811
[93 rows x 2 columns]
Storer Object¶
如果要检查存储的对象,请通过get_storer
检索。你可以使用这个程序来说明获取对象中的行数。
In [413]: store.get_storer('df_dc').nrows
Out[413]: 8
Multiple Table Queries¶
0.10.1中的新增功能是方法append_to_multiple
和select_as_multiple
,可以一次执行从多个表中追加/选择。想法是有一个表(称为选择器表),您索引最多/所有的列,并执行您的查询。其他表是具有与选择器表的索引匹配的索引的数据表。然后,您可以对选择器表执行非常快速的查询,但返回大量数据。此方法类似于具有非常宽的表,但是可以实现更高效的查询。
append_to_multiple
方法根据d
将给定的单个DataFrame拆分为多个表,该字典将表名映射到该表中所需的“列”列表。如果使用None代替列表,则该表将具有给定DataFrame的其余未指定列。参数selector
定义哪个表是选择器表(您可以从中进行查询)。参数dropna
将从输入DataFrame中删除行以确保表同步。这意味着,如果写入的其中一个表的行完全为np.NaN
,那么该行将从所有表中删除。
如果dropna
为False,则用户负责同步表格。Remember that entirely np.Nan
rows are not written to the HDFStore, so if you choose to call dropna=False
, some tables may have more rows than others, and therefore select_as_multiple
may not work or it may return unexpected results.
In [414]: df_mt = pd.DataFrame(randn(8, 6), index=pd.date_range('1/1/2000', periods=8),
.....: columns=['A', 'B', 'C', 'D', 'E', 'F'])
.....:
In [415]: df_mt['foo'] = 'bar'
In [416]: df_mt.ix[1, ('A', 'B')] = np.nan
# you can also create the tables individually
In [417]: store.append_to_multiple({'df1_mt': ['A', 'B'], 'df2_mt': None },
.....: df_mt, selector='df1_mt')
.....:
In [418]: store
Out[418]:
<class 'pandas.io.pytables.HDFStore'>
File path: store.h5
/df frame_table (typ->appendable,nrows->8,ncols->3,indexers->[index])
/df1_mt frame_table (typ->appendable,nrows->8,ncols->2,indexers->[index],dc->[A,B])
/df2_mt frame_table (typ->appendable,nrows->8,ncols->5,indexers->[index])
/df_coord frame_table (typ->appendable,nrows->1000,ncols->2,indexers->[index])
/df_dc frame_table (typ->appendable,nrows->8,ncols->5,indexers->[index],dc->[B,C,string,string2])
/df_mask frame_table (typ->appendable,nrows->1000,ncols->2,indexers->[index])
/df_mi frame_table (typ->appendable_multi,nrows->10,ncols->5,indexers->[index],dc->[bar,foo])
/df_mixed frame_table (typ->appendable,nrows->8,ncols->7,indexers->[index])
/dfeq frame_table (typ->appendable,nrows->10,ncols->1,indexers->[index],dc->[number])
/dfq frame_table (typ->appendable,nrows->10,ncols->4,indexers->[index],dc->[A,B,C,D])
/dftd frame_table (typ->appendable,nrows->10,ncols->3,indexers->[index],dc->[A,B,C])
/foo/bar/bah frame (shape->[8,3])
/wp wide_table (typ->appendable,nrows->20,ncols->2,indexers->[major_axis,minor_axis])
# individual tables were created
In [419]: store.select('df1_mt')
Out[419]:
A B
2000-01-01 0.714697 0.318215
2000-01-02 NaN NaN
2000-01-03 -0.086919 0.416905
2000-01-04 0.489131 -0.253340
2000-01-05 -0.382952 -0.397373
2000-01-06 0.538116 0.226388
2000-01-07 -2.073479 -0.115926
2000-01-08 -0.695400 0.402493
In [420]: store.select('df2_mt')
Out[420]:
C D E F foo
2000-01-01 0.607460 0.790907 0.852225 0.096696 bar
2000-01-02 0.811031 -0.356817 1.047085 0.664705 bar
2000-01-03 -0.764381 -0.287229 -0.089351 -1.035115 bar
2000-01-04 -1.948100 -0.116556 0.800597 -0.796154 bar
2000-01-05 -0.717627 0.156995 -0.344718 -0.171208 bar
2000-01-06 1.541729 0.205256 1.998065 0.953591 bar
2000-01-07 1.391070 0.303013 1.093347 -0.101000 bar
2000-01-08 -1.507639 0.089575 0.658822 -1.037627 bar
# as a multiple
In [421]: store.select_as_multiple(['df1_mt', 'df2_mt'], where=['A>0', 'B>0'],
.....: selector = 'df1_mt')
.....:
Out[421]:
A B C D E F foo
2000-01-01 0.714697 0.318215 0.607460 0.790907 0.852225 0.096696 bar
2000-01-06 0.538116 0.226388 1.541729 0.205256 1.998065 0.953591 bar
Delete from a Table¶
您可以通过指定where
选择性地从表中删除。在删除行时,了解PyTables
通过擦除行,然后移动以下数据删除行很重要。因此,删除可能是一个非常昂贵的操作,具体取决于数据的方向。这在更高维度的物体(Panel
和Panel4D
)中尤其如此。为了获得最佳效果,您需要将要删除的维度作为indexables
中的第一个维度。
数据按照indexables
的顺序排列(在磁盘上)。这里有一个简单的用例。您存储面板类型数据,日期在major_axis
中,而ID在minor_axis
中。然后数据交织如下:
- date_1 - id_1 - id_2 - 。 - id_n
- date_2 - id_1 - 。 - id_n
应当清楚,对major_axis
的删除操作将会相当快速,因为删除了一个块,然后移动以下数据。另一方面,对minor_axis
的删除操作将非常昂贵。在这种情况下,使用where
选择除缺少的数据之外的所有数据。
# returns the number of rows deleted
In [422]: store.remove('wp', 'major_axis>20000102' )
Out[422]: 12
In [423]: store.select('wp')
Out[423]:
<class 'pandas.core.panel.Panel'>
Dimensions: 2 (items) x 2 (major_axis) x 4 (minor_axis)
Items axis: Item1 to Item2
Major_axis axis: 2000-01-01 00:00:00 to 2000-01-02 00:00:00
Minor_axis axis: A to D
Notes & Caveats¶
Compression¶
PyTables
允许压缩存储的数据。这适用于各种商店,而不仅仅是表。
- 对于压缩级别(1-9,0是无压缩,默认值),传递
complevel=int
- 传递
complib=lib
其中lib是zlib, bzip2, lzo,
用于您喜欢的压缩库。
HDFStore
will use the file based compression scheme if no overriding complib
or complevel
options are provided. blosc
提供非常快速的压缩,是我最常用的。请注意,默认情况下可能不安装lzo
和bzip2
(通过Python)。
压缩文件中的所有对象
store_compressed = pd.HDFStore('store_compressed.h5', complevel=9, complib='blosc')
或即时压缩(这只适用于表)。您可以通过传递complevel=0
来关闭特定表的文件压缩
store.append('df', df, complib='zlib', complevel=5)
ptrepack¶
PyTables
在写入表之后压缩表时提供更好的写入性能,而不是在开始时打开压缩。您可以使用提供的PyTables
实用程序ptrepack
。此外,ptrepack
可以在事实之后更改压缩级别。
ptrepack --chunkshape=auto --propindexes --complevel=9 --complib=blosc in.h5 out.h5
Furthermore ptrepack in.h5 out.h5
will repack the file to allow you to reuse previously deleted space. 或者,可以简单地删除文件并再次写入,或使用copy
方法。
Caveats¶
警告
HDFStore
是不能写入的线程安全。底层的PyTables
只支持并发读取(通过线程或进程)。如果您需要同时读取和写入,则需要在单个进程中在单个线程中将这些操作序列化。否则将损坏您的数据。有关详细信息,请参阅(GH2397)。
- 如果使用锁来管理多个进程之间的写访问,则可能需要在释放写锁之前使用
fsync()
。为方便起见,您可以使用store.flush(fsync=True)
为您执行此操作。 - 一旦创建了
table
,它的项(Panel)/列(DataFrame)就是固定的;只能附加完全相同的列 - 请注意,时区(例如,
pytz.timezone('US/Eastern')
)在时区版本中不一定相等。因此,如果数据被本地化到HDFStore中使用一个版本的时区库的特定时区,并且数据被更新为另一个版本,则数据将被转换为UTC,因为这些时区不被视为相等。可以使用相同版本的时区库,也可以使用tz_convert
更新时区定义。
警告
PyTables
将显示NaturalNameWarning
。自然标识符只包含字母,数字和下划线,且不能以数字开头。其他标识符不能在where
子句中使用,通常是一个坏主意。
DataTypes¶
HDFStore
会将对象dtype映射到PyTables
底层dtype。这意味着以下类型已知可以工作:
类型 | 表示缺少的值 |
---|---|
浮动:float64, float32, float16 |
np.nan |
整数:int64, int32, int8, uint64,uint32, uint8 t5 > |
|
布尔 | |
datetime64[ns] |
NaT |
timedelta64[ns] |
NaT |
分类:见下面部分 | |
对象:strings |
np.nan |
unicode
列不受支持,WILL FAIL。
Categorical Data¶
版本0.15.2中的新功能。
将数据写入到包含category
dtype的HDFStore
中已在0.15.2中实现。查询的工作方式与它是一个对象数组相同。但是,category
类型化数据以更有效的方式存储。
In [424]: dfcat = pd.DataFrame({ 'A' : pd.Series(list('aabbcdba')).astype('category'),
.....: 'B' : np.random.randn(8) })
.....:
In [425]: dfcat
Out[425]:
A B
0 a 0.603273
1 a 0.262554
2 b -0.979586
3 b 2.132387
4 c 0.892485
5 d 1.996474
6 b 0.231425
7 a 0.980070
In [426]: dfcat.dtypes
Out[426]:
A category
B float64
dtype: object
In [427]: cstore = pd.HDFStore('cats.h5', mode='w')
In [428]: cstore.append('dfcat', dfcat, format='table', data_columns=['A'])
In [429]: result = cstore.select('dfcat', where="A in ['b','c']")
In [430]: result
Out[430]:
A B
2 b -0.979586
3 b 2.132387
4 c 0.892485
6 b 0.231425
In [431]: result.dtypes
Out[431]:
A category
B float64
dtype: object
警告
The format of the Categorical
is readable by prior versions of pandas (< 0.15.2), but will retrieve the data as an integer based column (e.g. the codes
). 但是,可以检索categories
可以,但需要用户使用显式元路径手动选择它们。
数据存储如下:
In [432]: cstore
Out[432]:
<class 'pandas.io.pytables.HDFStore'>
File path: cats.h5
/dfcat frame_table (typ->appendable,nrows->8,ncols->2,indexers->[index],dc->[A])
/dfcat/meta/A/meta series_table (typ->appendable,nrows->4,ncols->1,indexers->[index],dc->[values])
# to get the categories
In [433]: cstore.select('dfcat/meta/A/meta')
Out[433]:
0 a
1 b
2 c
3 d
dtype: object
String Columns¶
min_itemsize
HDFStore
的底层实现对字符串列使用固定列宽(itemsize)。字符串列itemsize计算为传递到第一个附加中的HDFStore
,的数据长度的最大值(对于该列)。Subsequent appends, may introduce a string for a column larger than the column can hold, an Exception will be raised (otherwise you could have a silent truncation of these columns, leading to loss of information). 在将来,我们可以放松这一点,并允许发生用户指定的截断。
将第一个表创建的min_itemsize
传递给先验指定特定字符串列的最小长度。min_itemsize
可以是整数,也可以是将列名称映射为整数的dict。您可以传递values
作为键,以允许所有可索引项或data_columns具有此min_itemsize。
从0.11.0开始,传递min_itemsize
dict将使所有传递的列自动创建为data_columns。
注意
如果您未传递任何data_columns
,则min_itemsize
将是传递的任何字符串的长度的最大值
In [434]: dfs = pd.DataFrame(dict(A = 'foo', B = 'bar'),index=list(range(5)))
In [435]: dfs
Out[435]:
A B
0 foo bar
1 foo bar
2 foo bar
3 foo bar
4 foo bar
# A and B have a size of 30
In [436]: store.append('dfs', dfs, min_itemsize = 30)
In [437]: store.get_storer('dfs').table
Out[437]:
/dfs/table (Table(5,)) ''
description := {
"index": Int64Col(shape=(), dflt=0, pos=0),
"values_block_0": StringCol(itemsize=30, shape=(2,), dflt='', pos=1)}
byteorder := 'little'
chunkshape := (963,)
autoindex := True
colindexes := {
"index": Index(6, medium, shuffle, zlib(1)).is_csi=False}
# A is created as a data_column with a size of 30
# B is size is calculated
In [438]: store.append('dfs2', dfs, min_itemsize = { 'A' : 30 })
In [439]: store.get_storer('dfs2').table
Out[439]:
/dfs2/table (Table(5,)) ''
description := {
"index": Int64Col(shape=(), dflt=0, pos=0),
"values_block_0": StringCol(itemsize=3, shape=(1,), dflt='', pos=1),
"A": StringCol(itemsize=30, shape=(), dflt='', pos=2)}
byteorder := 'little'
chunkshape := (1598,)
autoindex := True
colindexes := {
"A": Index(6, medium, shuffle, zlib(1)).is_csi=False,
"index": Index(6, medium, shuffle, zlib(1)).is_csi=False}
nan_rep
字符串列将使用nan_rep
字符串表示形式将np.nan
(缺少的值)序列化。默认为字符串值nan
。您可能无意中将实际的nan
值转换为缺失值。
In [440]: dfss = pd.DataFrame(dict(A = ['foo','bar','nan']))
In [441]: dfss
Out[441]:
A
0 foo
1 bar
2 nan
In [442]: store.append('dfss', dfss)
In [443]: store.select('dfss')
Out[443]:
A
0 foo
1 bar
2 NaN
# here you need to specify a different nan rep
In [444]: store.append('dfss2', dfss, nan_rep='_nan_')
In [445]: store.select('dfss2')
Out[445]:
A
0 foo
1 bar
2 nan
External Compatibility¶
HDFStore
以特定格式写入table
格式对象,适合生成对pandas对象的无丢失往返。为了外部兼容性,HDFStore
可以读取原生PyTables
格式表。
可以使用rhdf5
库(包网站)将可以轻松导入R
的HDFStore
)。创建一个表格式存储像这样:
In [446]: np.random.seed(1)
In [447]: df_for_r = pd.DataFrame({"first": np.random.rand(100),
.....: "second": np.random.rand(100),
.....: "class": np.random.randint(0, 2, (100,))},
.....: index=range(100))
.....:
In [448]: df_for_r.head()
Out[448]:
class first second
0 0 0.417022 0.326645
1 0 0.720324 0.527058
2 1 0.000114 0.885942
3 1 0.302333 0.357270
4 1 0.146756 0.908535
In [449]: store_export = pd.HDFStore('export.h5')
In [450]: store_export.append('df_for_r', df_for_r, data_columns=df_dc.columns)
In [451]: store_export
Out[451]:
<class 'pandas.io.pytables.HDFStore'>
File path: export.h5
/df_for_r frame_table (typ->appendable,nrows->100,ncols->3,indexers->[index])
在R中,这个文件可以使用rhdf5
库读入data.frame
对象。以下示例函数从值读取相应的列名称和数据值,并将它们组合到data.frame
中:
# Load values and column names for all datasets from corresponding nodes and
# insert them into one data.frame object.
library(rhdf5)
loadhdf5data <- function(h5File) {
listing <- h5ls(h5File)
# Find all data nodes, values are stored in *_values and corresponding column
# titles in *_items
data_nodes <- grep("_values", listing$name)
name_nodes <- grep("_items", listing$name)
data_paths = paste(listing$group[data_nodes], listing$name[data_nodes], sep = "/")
name_paths = paste(listing$group[name_nodes], listing$name[name_nodes], sep = "/")
columns = list()
for (idx in seq(data_paths)) {
# NOTE: matrices returned by h5read have to be transposed to to obtain
# required Fortran order!
data <- data.frame(t(h5read(h5File, data_paths[idx])))
names <- t(h5read(h5File, name_paths[idx]))
entry <- data.frame(data)
colnames(entry) <- names
columns <- append(columns, entry)
}
data <- data.frame(columns)
return(data)
}
现在您可以将DataFrame
导入R:
> data = loadhdf5data("transfer.hdf5")
> head(data)
first second class
1 0.4170220047 0.3266449 0
2 0.7203244934 0.5270581 0
3 0.0001143748 0.8859421 1
4 0.3023325726 0.3572698 1
5 0.1467558908 0.9085352 1
6 0.0923385948 0.6233601 1
注意
R函数列出整个HDF5文件的内容,并从所有匹配的节点组装data.frame
对象,因此,如果您已存储多个DataFrame
对象到一个单一的HDF5文件。
Backwards Compatibility¶
HDFStore
的0.10.1可读取在先前版本的pandas中创建的表,但不支持使用之前(未记录)方法的查询术语。HDFStore
将会发出警告。您必须读取整个文件,并使用新格式写出,使用方法copy
以利用更新。组属性pandas_version
包含版本信息。copy
需要一些选项,请参阅docstring。
# a legacy store
In [452]: legacy_store = pd.HDFStore(legacy_file_path,'r')
In [453]: legacy_store
Out[453]:
<class 'pandas.io.pytables.HDFStore'>
File path: /home/joris/scipy/pandas/doc/source/_static/legacy_0.10.h5
/a series (shape->[30])
/b frame (shape->[30,4])
/df1_mixed frame_table [0.10.0] (typ->appendable,nrows->30,ncols->11,indexers->[index])
/foo/bar wide (shape->[3,30,4])
/p1_mixed wide_table [0.10.0] (typ->appendable,nrows->120,ncols->9,indexers->[major_axis,minor_axis])
/p4d_mixed ndim_table [0.10.0] (typ->appendable,nrows->360,ncols->9,indexers->[items,major_axis,minor_axis])
# copy (and return the new handle)
In [454]: new_store = legacy_store.copy('store_new.h5')
In [455]: new_store
Out[455]:
<class 'pandas.io.pytables.HDFStore'>
File path: store_new.h5
/a series (shape->[30])
/b frame (shape->[30,4])
/df1_mixed frame_table (typ->appendable,nrows->30,ncols->11,indexers->[index])
/foo/bar wide (shape->[3,30,4])
/p1_mixed wide_table (typ->appendable,nrows->120,ncols->9,indexers->[major_axis,minor_axis])
/p4d_mixed wide_table (typ->appendable,nrows->360,ncols->9,indexers->[items,major_axis,minor_axis])
In [456]: new_store.close()
Performance¶
- 与
fixed
存储相比,tables
格式具有写入性能损失。好处是附加/删除和查询(可能非常大量的数据)的能力。与普通商店相比,写入时间通常更长。查询时间可以很快,特别是在索引轴上。 - 您可以将
chunksize=<int>
传递到append
,指定写入chunksize(默认值为50000)。这将大大降低写入时的内存使用率。 - 您可以将
expectedrows=<int>
传递到第一个append
,以设置PyTables
预期的预期行数TOTAL。这将优化读/写性能。 - 重复的行可以写入表,但在选择中被过滤掉(最后一个项被选择;因此,一个表在主要,次要对上是唯一的)
- 如果您尝试存储将由PyTables(而不是存储为地方性类型)选择的类型,将会引发
PerformanceWarning
。有关详细信息和一些解决方案,请参阅此处。
Experimental¶
HDFStore支持Panel4D
存储。
In [457]: p4d = pd.Panel4D({ 'l1' : wp })
In [458]: p4d
Out[458]:
<class 'pandas.core.panelnd.Panel4D'>
Dimensions: 1 (labels) x 2 (items) x 5 (major_axis) x 4 (minor_axis)
Labels axis: l1 to l1
Items axis: Item1 to Item2
Major_axis axis: 2000-01-01 00:00:00 to 2000-01-05 00:00:00
Minor_axis axis: A to D
In [459]: store.append('p4d', p4d)
In [460]: store
Out[460]:
<class 'pandas.io.pytables.HDFStore'>
File path: store.h5
/df frame_table (typ->appendable,nrows->8,ncols->3,indexers->[index])
/df1_mt frame_table (typ->appendable,nrows->8,ncols->2,indexers->[index],dc->[A,B])
/df2_mt frame_table (typ->appendable,nrows->8,ncols->5,indexers->[index])
/df_coord frame_table (typ->appendable,nrows->1000,ncols->2,indexers->[index])
/df_dc frame_table (typ->appendable,nrows->8,ncols->5,indexers->[index],dc->[B,C,string,string2])
/df_mask frame_table (typ->appendable,nrows->1000,ncols->2,indexers->[index])
/df_mi frame_table (typ->appendable_multi,nrows->10,ncols->5,indexers->[index],dc->[bar,foo])
/df_mixed frame_table (typ->appendable,nrows->8,ncols->7,indexers->[index])
/dfeq frame_table (typ->appendable,nrows->10,ncols->1,indexers->[index],dc->[number])
/dfq frame_table (typ->appendable,nrows->10,ncols->4,indexers->[index],dc->[A,B,C,D])
/dfs frame_table (typ->appendable,nrows->5,ncols->2,indexers->[index])
/dfs2 frame_table (typ->appendable,nrows->5,ncols->2,indexers->[index],dc->[A])
/dfss frame_table (typ->appendable,nrows->3,ncols->1,indexers->[index])
/dfss2 frame_table (typ->appendable,nrows->3,ncols->1,indexers->[index])
/dftd frame_table (typ->appendable,nrows->10,ncols->3,indexers->[index],dc->[A,B,C])
/foo/bar/bah frame (shape->[8,3])
/p4d wide_table (typ->appendable,nrows->40,ncols->1,indexers->[items,major_axis,minor_axis])
/wp wide_table (typ->appendable,nrows->8,ncols->2,indexers->[major_axis,minor_axis])
默认情况下,这些索引为三个轴项, major_axis, minor_axis
。在AppendableTable
上,可以使用第一个追加设置不同的索引方案,具体取决于您要如何存储数据。将axes
关键字与尺寸列表(当前必须比对象的总尺寸小1)相关联。这在创建表之后不能更改。
In [461]: store.append('p4d2', p4d, axes=['labels', 'major_axis', 'minor_axis'])
In [462]: store
Out[462]:
<class 'pandas.io.pytables.HDFStore'>
File path: store.h5
/df frame_table (typ->appendable,nrows->8,ncols->3,indexers->[index])
/df1_mt frame_table (typ->appendable,nrows->8,ncols->2,indexers->[index],dc->[A,B])
/df2_mt frame_table (typ->appendable,nrows->8,ncols->5,indexers->[index])
/df_coord frame_table (typ->appendable,nrows->1000,ncols->2,indexers->[index])
/df_dc frame_table (typ->appendable,nrows->8,ncols->5,indexers->[index],dc->[B,C,string,string2])
/df_mask frame_table (typ->appendable,nrows->1000,ncols->2,indexers->[index])
/df_mi frame_table (typ->appendable_multi,nrows->10,ncols->5,indexers->[index],dc->[bar,foo])
/df_mixed frame_table (typ->appendable,nrows->8,ncols->7,indexers->[index])
/dfeq frame_table (typ->appendable,nrows->10,ncols->1,indexers->[index],dc->[number])
/dfq frame_table (typ->appendable,nrows->10,ncols->4,indexers->[index],dc->[A,B,C,D])
/dfs frame_table (typ->appendable,nrows->5,ncols->2,indexers->[index])
/dfs2 frame_table (typ->appendable,nrows->5,ncols->2,indexers->[index],dc->[A])
/dfss frame_table (typ->appendable,nrows->3,ncols->1,indexers->[index])
/dfss2 frame_table (typ->appendable,nrows->3,ncols->1,indexers->[index])
/dftd frame_table (typ->appendable,nrows->10,ncols->3,indexers->[index],dc->[A,B,C])
/foo/bar/bah frame (shape->[8,3])
/p4d wide_table (typ->appendable,nrows->40,ncols->1,indexers->[items,major_axis,minor_axis])
/p4d2 wide_table (typ->appendable,nrows->20,ncols->2,indexers->[labels,major_axis,minor_axis])
/wp wide_table (typ->appendable,nrows->8,ncols->2,indexers->[major_axis,minor_axis])
In [463]: store.select('p4d2', [ pd.Term('labels=l1'), pd.Term('items=Item1'), pd.Term('minor_axis=A_big_strings') ])
Out[463]:
<class 'pandas.core.panelnd.Panel4D'>
Dimensions: 0 (labels) x 1 (items) x 0 (major_axis) x 0 (minor_axis)
Labels axis: None
Items axis: Item1 to Item1
Major_axis axis: None
Minor_axis axis: None
SQL Queries¶
pandas.io.sql
模块提供了一组查询包装器,以便于数据检索和减少对特定于数据库的API的依赖。数据库抽象由SQLAlchemy(如果已安装)提供。此外,您将需要一个用于数据库的驱动程序库。这种驱动程序的示例是PostgreSQL的psycopg2或MySQL的pymysql。对于SQLite,默认情况下包含在Python的标准库中。您可以在SQLAlchemy docs中找到每种SQL方言的支持的驱动程序的概述。
版本0.14.0中的新功能。
如果未安装SQLAlchemy,则仅为sqlite提供回退(对于mysql,为向后兼容性,但不推荐使用,将在以后的版本中删除)。此模式需要一个尊重Python DB-API的Python数据库适配器。
有关一些高级策略,另见一些cookbook examples。
主要功能有:
read_sql_table (table_name,con [,schema,...]) |
将SQL数据库表读入DataFrame。 |
read_sql_query (sql,con [,index_col,...]) |
将SQL查询读入DataFrame。 |
read_sql (sql,con [,index_col,...]) |
将SQL查询或数据库表读入DataFrame。 |
DataFrame.to_sql (name,con [,flavor,...]) |
将存储在DataFrame中的记录写入SQL数据库。 |
注意
函数read_sql()
是围绕read_sql_table()
和read_sql_query()
(以及为了向后兼容)的方便包装,取决于提供的输入(数据库表名或sql查询)。如果表名称具有特殊字符,则不需要引用。
在以下示例中,我们使用SQlite SQL数据库引擎。您可以使用临时SQLite数据库,其中数据存储在“内存”中。
要使用SQLAlchemy连接,可以使用create_engine()
函数从数据库URI创建引擎对象。每个要连接的数据库只需创建引擎一次。有关create_engine()
和URI格式的更多信息,请参阅下面的示例和SQLAlchemy 文档
In [464]: from sqlalchemy import create_engine
# Create your engine.
In [465]: engine = create_engine('sqlite:///:memory:')
with engine.connect() as conn, conn.begin():
data = pd.read_sql_table('data', conn)
Writing DataFrames¶
假设以下数据在DataFrame data
中,我们可以使用to_sql()
将其插入数据库。
ID | 日期 | Col_1 | Col_2 | Col_3 |
---|---|---|---|---|
26 | 2012-10-18 | X | 25.7 | 真正 |
42 | 2012-10-19 | Y | -12.4 | 假 |
63 | 2012-10-20 | Z | 5.73 | 真正 |
In [466]: data.to_sql('data', engine)
对于某些数据库,由于超过了数据包大小限制,写入大型DataFrames可能会导致错误。这可以通过在调用to_sql
时设置chunksize
参数来避免。例如,以下将data
以批处理形式批量写入数据库:每次1000行:
In [467]: data.to_sql('data_chunked', engine, chunksize=1000)
SQL data types¶
to_sql()
将尝试根据数据的dtype将数据映射到适当的SQL数据类型。当您有dtype object
的列时,pandas将尝试推断数据类型。
您可以通过使用dtype
参数指定任何列的所需SQL类型来覆盖默认类型。此参数需要一个字典将列名称映射到SQLAlchemy类型(或sqlite3回退模式的字符串)。例如,指定对字符串列使用sqlalchemy String
类型而不是默认的Text
类型:
In [468]: from sqlalchemy.types import String
In [469]: data.to_sql('data_dtype', engine, dtype={'Col_1': String})
注意
由于timedelta在不同数据库风格中的支持有限,因此类型为timedelta64
的列将作为整数值写入数据库中,并将生成警告。
注意
category
dtype的列将转换为密集表示,如您在np.asarray(categorical)
(例如,对于字符串类别,这将提供一个字符串数组)。因此,读取数据库表时,不会生成分类。
Reading Tables¶
read_sql_table()
将读取给定表名称和可选的要读取的列子集的数据库表。
注意
要使用read_sql_table()
,您必须安装SQLAlchemy可选依赖项。
In [470]: pd.read_sql_table('data', engine)
Out[470]:
index id Date Col_1 Col_2 Col_3
0 0 26 2010-10-18 X 27.50 True
1 1 42 2010-10-19 Y -12.50 False
2 2 63 2010-10-20 Z 5.73 True
您还可以将列的名称指定为DataFrame索引,并指定要读取的列的子集。
In [471]: pd.read_sql_table('data', engine, index_col='id')
Out[471]:
index Date Col_1 Col_2 Col_3
id
26 0 2010-10-18 X 27.50 True
42 1 2010-10-19 Y -12.50 False
63 2 2010-10-20 Z 5.73 True
In [472]: pd.read_sql_table('data', engine, columns=['Col_1', 'Col_2'])
Out[472]:
Col_1 Col_2
0 X 27.50
1 Y -12.50
2 Z 5.73
您可以明确强制将列解析为日期:
In [473]: pd.read_sql_table('data', engine, parse_dates=['Date'])
Out[473]:
index id Date Col_1 Col_2 Col_3
0 0 26 2010-10-18 X 27.50 True
1 1 42 2010-10-19 Y -12.50 False
2 2 63 2010-10-20 Z 5.73 True
如果需要,您可以显式指定格式字符串或要传递给pandas.to_datetime()
的参数的dict:
pd.read_sql_table('data', engine, parse_dates={'Date': '%Y-%m-%d'})
pd.read_sql_table('data', engine, parse_dates={'Date': {'format': '%Y-%m-%d %H:%M:%S'}})
您可以使用has_table()
检查表是否存在
Schema support¶
版本0.15.0中的新功能。
通过read_sql_table()
和to_sql()
函数中的schema
关键字支持读取和写入不同模式。注意,这取决于数据库风格(sqlite没有模式)。例如:
df.to_sql('table', engine, schema='other_schema')
pd.read_sql_table('table', engine, schema='other_schema')
Querying¶
您可以在read_sql_query()
函数中使用原始SQL进行查询。在这种情况下,必须使用适合于数据库的SQL变量。当使用SQLAlchemy时,还可以传递SQLAlchemy Expression语言构造,这是数据库不可知的。
In [474]: pd.read_sql_query('SELECT * FROM data', engine)
Out[474]:
index id Date Col_1 Col_2 Col_3
0 0 26 2010-10-18 00:00:00.000000 X 27.50 1
1 1 42 2010-10-19 00:00:00.000000 Y -12.50 0
2 2 63 2010-10-20 00:00:00.000000 Z 5.73 1
当然,你可以指定一个更“复杂”的查询。
In [475]: pd.read_sql_query("SELECT id, Col_1, Col_2 FROM data WHERE id = 42;", engine)
Out[475]:
id Col_1 Col_2
0 42 Y -12.5
read_sql_query()
函数支持chunksize
参数。指定这将返回一个迭代器通过查询结果的块:
In [476]: df = pd.DataFrame(np.random.randn(20, 3), columns=list('abc'))
In [477]: df.to_sql('data_chunks', engine, index=False)
In [478]: for chunk in pd.read_sql_query("SELECT * FROM data_chunks", engine, chunksize=5):
.....: print(chunk)
.....:
a b c
0 0.280665 -0.073113 1.160339
1 0.369493 1.904659 1.111057
2 0.659050 -1.627438 0.602319
3 0.420282 0.810952 1.044442
4 -0.400878 0.824006 -0.562305
a b c
0 1.954878 -1.331952 -1.760689
1 -1.650721 -0.890556 -1.119115
2 1.956079 -0.326499 -1.342676
3 1.114383 -0.586524 -1.236853
4 0.875839 0.623362 -0.434957
a b c
0 1.407540 0.129102 1.616950
1 0.502741 1.558806 0.109403
2 -1.219744 2.449369 -0.545774
3 -0.198838 -0.700399 -0.203394
4 0.242669 0.201830 0.661020
a b c
0 1.792158 -0.120465 -1.233121
1 -1.182318 -0.665755 -1.674196
2 0.825030 -0.498214 -0.310985
3 -0.001891 -1.396620 -0.861316
4 0.674712 0.618539 -0.443172
您还可以运行纯查询,而不使用execute()
创建数据帧。这对于不返回值的查询很有用,例如INSERT。这在功能上等同于在SQLAlchemy引擎或db连接对象上调用execute
。同样,您必须使用适合您的数据库的SQL语法变体。
from pandas.io import sql
sql.execute('SELECT * FROM table_name', engine)
sql.execute('INSERT INTO table_name VALUES(?, ?, ?)', engine, params=[('id', 1, 12.2, True)])
Engine connection examples¶
要使用SQLAlchemy连接,可以使用create_engine()
函数从数据库URI创建引擎对象。每个要连接的数据库只需创建引擎一次。
from sqlalchemy import create_engine
engine = create_engine('postgresql://scott:tiger@localhost:5432/mydatabase')
engine = create_engine('mysql+mysqldb://scott:tiger@localhost/foo')
engine = create_engine('oracle://scott:[email protected]:1521/sidname')
engine = create_engine('mssql+pyodbc://mydsn')
# sqlite://<nohostname>/<path>
# where <path> is relative:
engine = create_engine('sqlite:///foo.db')
# or absolute, starting with a slash:
engine = create_engine('sqlite:////absolute/path/to/foo.db')
有关更多信息,请参见SQLAlchemy 文档示例
Advanced SQLAlchemy queries¶
您可以使用SQLAlchemy结构来描述您的查询。
使用sqlalchemy.text()
以后端中性方式指定查询参数
In [479]: import sqlalchemy as sa
In [480]: pd.read_sql(sa.text('SELECT * FROM data where Col_1=:col1'), engine, params={'col1': 'X'})
Out[480]:
index id Date Col_1 Col_2 Col_3
0 0 26 2010-10-18 00:00:00.000000 X 27.5 1
如果您有数据库的SQLAlchemy描述,可以使用SQLAlchemy表达式表达条件
In [481]: metadata = sa.MetaData()
In [482]: data_table = sa.Table('data', metadata,
.....: sa.Column('index', sa.Integer),
.....: sa.Column('Date', sa.DateTime),
.....: sa.Column('Col_1', sa.String),
.....: sa.Column('Col_2', sa.Float),
.....: sa.Column('Col_3', sa.Boolean),
.....: )
.....:
In [483]: pd.read_sql(sa.select([data_table]).where(data_table.c.Col_3 == True), engine)
Out[483]:
index Date Col_1 Col_2 Col_3
0 0 2010-10-18 X 27.50 True
1 2 2010-10-20 Z 5.73 True
您可以使用sqlalchemy.bindparam()
将SQLAlchemy表达式与传递给read_sql()
In [484]: import datetime as dt
In [485]: expr = sa.select([data_table]).where(data_table.c.Date > sa.bindparam('date'))
In [486]: pd.read_sql(expr, engine, params={'date': dt.datetime(2010, 10, 18)})
Out[486]:
index Date Col_1 Col_2 Col_3
0 1 2010-10-19 Y -12.50 False
1 2 2010-10-20 Z 5.73 True
Sqlite fallback¶
不使用SQLAlchemy支持sqlite的使用。此模式需要一个尊重Python DB-API的Python数据库适配器。
您可以创建如下所示的连接:
import sqlite3
con = sqlite3.connect(':memory:')
然后发出以下查询:
data.to_sql('data', cnx)
pd.read_sql_query("SELECT * FROM data", con)
Google BigQuery (Experimental)¶
版本0.13.0中的新功能。
pandas.io.gbq
模块为Google的BigQuery分析网络服务提供了一个包装器,以简化使用类似SQL的查询从BigQuery表中检索结果。结果集将解析为具有从源表派生的形状和数据类型的pandas DataFrame。此外,DataFrames可以插入新的BigQuery表或附加到现有表。
您将需要安装一些额外的依赖:
警告
要使用此模块,您需要一个有效的BigQuery帐户。有关服务本身的详细信息,请参阅BigQuery文档。
主要功能有:
read_gbq (query [,project_id,index_col,...]) |
从Google BigQuery载入数据。 |
to_gbq (dataframe,destination_table,project_id) |
将DataFrame写入Google BigQuery表格。 |
Authentication¶
版本0.18.0中的新功能。
Google BigQuery
服务的验证是通过OAuth 2.0
进行。可以使用用户帐户凭据或服务帐户凭据进行身份验证。
使用用户帐户凭据进行身份验证与浏览器窗口中的提示一样简单,会自动为您打开。您将使用产品名称pandas GBQ
向指定的BigQuery
帐户验证身份。它只能在本地主机上。Pandas当前不支持使用用户帐户凭据的远程身份验证。有关身份验证机制的其他信息,请参见此处。
可以通过'private_key'参数进行具有服务帐户凭据的身份验证。当在远程服务器上工作时,此方法特别有用(例如。远程主机上的jupyter iPython笔记本)。有关服务帐户的其他信息,请访问此处。
您需要安装附加的依赖项:oauth2client。
还可以通过应用 默认 凭据
这仅在未提供参数private_key
时有效。此方法还要求可以从代码运行的环境中获取凭据。否则,将使用OAuth2客户端身份验证。有关应用程序默认凭据的其他信息。
版本0.19.0中的新功能。
注意
'private_key'参数可以设置为JSON格式的服务帐户密钥的文件路径,或JSON格式的服务帐户密钥的密钥内容。
注意
您可以点击此处从Google开发者控制台获取私钥。使用JSON键类型。
Querying¶
假设您要使用read_gbq()
函数将现有BigQuery表中的所有数据加载到DataFrame:test_dataset.test_table
# Insert your BigQuery Project ID Here
# Can be found in the Google web console
projectid = "xxxxxxxx"
data_frame = pd.read_gbq('SELECT * FROM test_dataset.test_table', projectid)
您可以定义BigQuery中的哪个列用作目标DataFrame中的索引以及首选列顺序,如下所示:
data_frame = pd.read_gbq('SELECT * FROM test_dataset.test_table',
index_col='index_column_name',
col_order=['col1', 'col2', 'col3'], projectid)
注意
您可以在Google开发人员控制台中找到您的专案ID。
注意
您可以通过默认为True
的verbose
标志切换详细输出。
注意
dialect
参数可用于指示是否使用BigQuery的'legacy'
SQL或BigQuery的'standard'
SQL(测试版)。默认值为'legacy'
。有关BigQuery标准SQL的详情,请参阅BigQuery SQL参考
Writing DataFrames¶
假设我们要使用to_gbq()
将DataFrame df
写入BigQuery表格中。
In [487]: df = pd.DataFrame({'my_string': list('abc'),
.....: 'my_int64': list(range(1, 4)),
.....: 'my_float64': np.arange(4.0, 7.0),
.....: 'my_bool1': [True, False, True],
.....: 'my_bool2': [False, True, False],
.....: 'my_dates': pd.date_range('now', periods=3)})
.....:
In [488]: df
Out[488]:
my_bool1 my_bool2 my_dates my_float64 my_int64 my_string
0 True False 2016-12-24 18:33:33.411047 4.0 1 a
1 False True 2016-12-25 18:33:33.411047 5.0 2 b
2 True False 2016-12-26 18:33:33.411047 6.0 3 c
In [489]: df.dtypes
Out[489]:
my_bool1 bool
my_bool2 bool
my_dates datetime64[ns]
my_float64 float64
my_int64 int64
my_string object
dtype: object
df.to_gbq('my_dataset.my_table', projectid)
注意
如果目标表和目标数据集不存在,将自动创建它们。
if_exists
参数可用于指示是否'fail'
,'replace'
或'append'
if目标表已存在。默认值为'fail'
。
例如,假设if_exists
设置为'fail'
。如果目标表已存在,以下代码段将产生TableCreationError
。
df.to_gbq('my_dataset.my_table', projectid, if_exists='fail')
注意
如果if_exists
参数设置为'append'
,则将使用定义的表模式和列类型将目标数据帧写入表。数据帧必须与结构和数据类型中的目标表相匹配。如果if_exists
参数设置为'replace'
,并且现有表具有不同的模式,则将强制延迟2分钟以确保新模式已传播在Google环境中。请参阅Google BigQuery问题191。
写入大型DataFrames可能会由于超出大小限制而导致错误。这可以通过在调用to_gbq()
时设置chunksize
参数来避免。例如,以下将df
以批处理形式批量写入BigQuery表中:每次10000行:
df.to_gbq('my_dataset.my_table', projectid, chunksize=10000)
您还可以通过默认为True
的verbose
标志查看您的帖子的进度。例如:
In [8]: df.to_gbq('my_dataset.my_table', projectid, chunksize=10000, verbose=True)
Streaming Insert is 10% Complete
Streaming Insert is 20% Complete
Streaming Insert is 30% Complete
Streaming Insert is 40% Complete
Streaming Insert is 50% Complete
Streaming Insert is 60% Complete
Streaming Insert is 70% Complete
Streaming Insert is 80% Complete
Streaming Insert is 90% Complete
Streaming Insert is 100% Complete
注意
如果在将数据流式传输到BigQuery时发生错误,请参阅排查BigQuery错误。
注意
BigQuery SQL查询语言有一些异常,请参阅BigQuery查询参考文档。
注意
虽然BigQuery使用类似SQL的语法,但它在功能,API限制(查询或上传的大小和数量)以及Google对服务使用收费方面与传统数据库有一些重要差异。由于服务似乎在变化和发展,因此您应经常参阅Google BigQuery文档。BiqQuery最适合快速分析大量数据,但不能直接替换事务数据库。
Creating BigQuery Tables¶
警告
从0.17开始,函数generate_bq_schema()
已被弃用,并将在未来版本中删除。
从0.15.2开始,gbq模块具有函数generate_bq_schema()
,它将产生指定的pandas DataFrame的字典表示模式。
In [10]: gbq.generate_bq_schema(df, default_type='STRING')
Out[10]: {'fields': [{'name': 'my_bool1', 'type': 'BOOLEAN'},
{'name': 'my_bool2', 'type': 'BOOLEAN'},
{'name': 'my_dates', 'type': 'TIMESTAMP'},
{'name': 'my_float64', 'type': 'FLOAT'},
{'name': 'my_int64', 'type': 'INTEGER'},
{'name': 'my_string', 'type': 'STRING'}]}
注意
如果您删除并重新创建具有相同名称但表格架构不同的BigQuery表,则必须等待2分钟才能将数据流式传输到表中。作为解决方法,请考虑使用不同的名称创建新表。请参阅Google BigQuery问题191。
Stata Format¶
版本0.12.0中的新功能。
Writing to Stata format¶
方法to_stata()
会将DataFrame写入.dta文件。此文件的格式版本始终为115(Stata 12)。
In [490]: df = pd.DataFrame(randn(10, 2), columns=list('AB'))
In [491]: df.to_stata('stata.dta')
Stata data files have limited data type support; only strings with 244 or fewer characters, int8
, int16
, int32
, float32
and float64
can be stored in .dta
files. 此外,Stata保留某些值以表示缺失的数据。导出特定数据类型的Stata中允许范围之外的非缺失值将会将该变量重新键入下一个较大的大小。例如,在Stata中,int8
的值被限制在-127和100之间,因此值大于100的变量将触发到int16
的转换。浮点数据类型中的nan
值被存储为基本丢失数据类型(.
在Stata)。
注意
不能导出整数数据类型的缺失数据值。
The Stata writer gracefully handles other data types including int64
, bool
, uint8
, uint16
, uint32
by casting to the smallest supported type that can represent the data. For example, data with a type of uint8
will be cast to int8
if all values are less than 100 (the upper bound for non-missing int8
data in Stata), or, if values are outside of this range, the variable is cast to int16
.
警告
如果int64
值大于2 ** 53,则从int64
到float64
的转换可能会导致精度损失。
警告
StataWriter
和to_stata()
仅支持包含最多244个字符的固定宽度字符串,这是版本115 dta文件格式强加的限制。尝试使用长度超过244个字符的字符串写入Stata dta文件会引发ValueError
。
Reading from Stata format¶
顶层函数read_stata
将读取一个dta文件,并返回一个DataFrame或一个StataReader
,用于以增量方式读取文件。
In [492]: pd.read_stata('stata.dta')
Out[492]:
index A B
0 0 1.810535 -1.305727
1 1 -0.344987 -0.230840
2 2 -2.793085 1.937529
3 3 0.366332 -1.044589
4 4 2.051173 0.585662
5 5 0.429526 -0.606998
6 6 0.106223 -1.525680
7 7 0.795026 -0.374438
8 8 0.134048 1.202055
9 9 0.284748 0.262467
版本0.16.0中的新功能。
指定chunksize
会生成一个StataReader
实例,用于一次从文件中读取chunksize
行。StataReader
对象可以用作迭代器。
In [493]: reader = pd.read_stata('stata.dta', chunksize=3)
In [494]: for df in reader:
.....: print(df.shape)
.....:
(3, 3)
(3, 3)
(3, 3)
(1, 3)
对于更细粒度的控制,使用iterator=True
并在每次调用read()
时指定chunksize
。
In [495]: reader = pd.read_stata('stata.dta', iterator=True)
In [496]: chunk1 = reader.read(5)
In [497]: chunk2 = reader.read(5)
目前,index
作为列检索。
参数convert_categoricals
指示是否应读取值标签,并使用它们从中创建Categorical
变量。值标签也可以通过函数value_labels
检索,这需要在使用之前调用read()
。
参数convert_missing
指示是否应保留Stata中的缺失值表示。如果False
(默认值),则缺失值表示为np.nan
。如果True
,则使用StataMissingValue
对象表示缺失值,包含缺少值的列将具有object
数据类型。
注意
read_stata()
和StataReader
支持.dta格式113-115(Stata 10-12),117(Stata 13)和118(Stata 14)。
注意
设置preserve_dtypes=False
将向上转换为标准的pandas数据类型:对于所有整数类型为int64
,对于浮点数据为float64
。默认情况下,Stata数据类型在导入时保留。
Categorical Data¶
版本0.15.2中的新功能。
Categorical
数据可以作为值标记数据导出到Stata数据文件。导出的数据由作为整数数据值的底层类别代码和作为值标签的类别组成。Stata没有显式等效于Categorical
,并且有关变量是否有序的信息在导出时会丢失。
警告
Stata仅支持字符串值标签,因此导出数据时,类别上调用str
。导出具有非字符串类别的Categorical
变量会产生警告,如果类别的str
表示不唯一,则可能导致信息丢失。
使用关键字参数convert_categoricals
(默认情况下为True
),可以类似地将Stata数据文件中的标签数据导入为Categorical
关键字参数order_categoricals
(默认情况下为True
)决定导入的Categorical
变量是否有序。
注意
导入分类数据时,Stata数据文件中的变量值不会保留,因为Categorical
变量始终使用整数数据类型-1
和n-1
其中n
是类别的数量。如果需要Stata数据文件中的原始值,可以通过设置convert_categoricals=False
导入这些值,这将导入原始数据(但不导入变量标签)。The original values can be matched to the imported categorical data since there is a simple mapping between the original Stata data values and the category codes of imported Categorical variables: missing values are assigned code -1
, and the smallest original value is assigned 0
, the second smallest is assigned 1
and so on until the largest original value is assigned the code n-1
.
注意
Stata支持部分标记的系列。这些系列具有一些但不是所有数据值的值标签。Importing a partially labeled series will produce a Categorical
with string categories for the values that are labeled and numeric categories for values with no label.
SAS Formats¶
版本0.17.0中的新功能。
顶层函数read_sas()
可读取SAS xport(.XPT)和SAS7BDAT(.sas7bdat)格式文件在v0.18.0中添加。
SAS文件只包含两种值类型:ASCII文本和浮点值(通常为8字节,但有时被截断)。对于xport文件,没有自动类型转换为整数,日期或分类。对于SAS7BDAT文件,格式代码可以允许日期变量自动转换为日期。默认情况下,读取整个文件并将其作为DataFrame
返回。
指定chunksize
或使用iterator=True
获取读取器对象(XportReader
或SAS7BDATReader
), 。阅读器对象还具有包含有关文件及其变量的附加信息的属性。
读取SAS7BDAT文件:
df = pd.read_sas('sas_data.sas7bdat')
获取一个迭代器,并一次读取一个XPORT文件10万行:
rdr = pd.read_sas('sas_xport.xpt', chunk=100000)
for chunk in rdr:
do_something(chunk)
xport文件格式的规范可从SAS网站获取。
没有官方文档可用于SAS7BDAT格式。
Other file formats¶
pandas本身只支持有一组有限的文件格式的IO,它们清楚地映射到它的表格数据模型。对于从pandas中读取和写入其他文件格式,我们推荐来自更广泛的社区的这些包。
Performance Considerations¶
这是使用pandas 0.13.1的各种IO方法的非正式比较。
In [1]: df = pd.DataFrame(randn(1000000,2),columns=list('AB'))
In [2]: df.info()
<class 'pandas.core.frame.DataFrame'>
Int64Index: 1000000 entries, 0 to 999999
Data columns (total 2 columns):
A 1000000 non-null float64
B 1000000 non-null float64
dtypes: float64(2)
memory usage: 22.9 MB
写作
In [14]: %timeit test_sql_write(df)
1 loops, best of 3: 6.24 s per loop
In [15]: %timeit test_hdf_fixed_write(df)
1 loops, best of 3: 237 ms per loop
In [26]: %timeit test_hdf_fixed_write_compress(df)
1 loops, best of 3: 245 ms per loop
In [16]: %timeit test_hdf_table_write(df)
1 loops, best of 3: 901 ms per loop
In [27]: %timeit test_hdf_table_write_compress(df)
1 loops, best of 3: 952 ms per loop
In [17]: %timeit test_csv_write(df)
1 loops, best of 3: 3.44 s per loop
读
In [18]: %timeit test_sql_read()
1 loops, best of 3: 766 ms per loop
In [19]: %timeit test_hdf_fixed_read()
10 loops, best of 3: 19.1 ms per loop
In [28]: %timeit test_hdf_fixed_read_compress()
10 loops, best of 3: 36.3 ms per loop
In [20]: %timeit test_hdf_table_read()
10 loops, best of 3: 39 ms per loop
In [29]: %timeit test_hdf_table_read_compress()
10 loops, best of 3: 60.6 ms per loop
In [22]: %timeit test_csv_read()
1 loops, best of 3: 620 ms per loop
磁盘空间(以字节为单位)
25843712 Apr 8 14:11 test.sql
24007368 Apr 8 14:11 test_fixed.hdf
15580682 Apr 8 14:11 test_fixed_compress.hdf
24458444 Apr 8 14:11 test_table.hdf
16797283 Apr 8 14:11 test_table_compress.hdf
46152810 Apr 8 14:11 test.csv
这里是代码
import sqlite3
import os
from pandas.io import sql
df = pd.DataFrame(randn(1000000,2),columns=list('AB'))
def test_sql_write(df):
if os.path.exists('test.sql'):
os.remove('test.sql')
sql_db = sqlite3.connect('test.sql')
df.to_sql(name='test_table', con=sql_db)
sql_db.close()
def test_sql_read():
sql_db = sqlite3.connect('test.sql')
pd.read_sql_query("select * from test_table", sql_db)
sql_db.close()
def test_hdf_fixed_write(df):
df.to_hdf('test_fixed.hdf','test',mode='w')
def test_hdf_fixed_read():
pd.read_hdf('test_fixed.hdf','test')
def test_hdf_fixed_write_compress(df):
df.to_hdf('test_fixed_compress.hdf','test',mode='w',complib='blosc')
def test_hdf_fixed_read_compress():
pd.read_hdf('test_fixed_compress.hdf','test')
def test_hdf_table_write(df):
df.to_hdf('test_table.hdf','test',mode='w',format='table')
def test_hdf_table_read():
pd.read_hdf('test_table.hdf','test')
def test_hdf_table_write_compress(df):
df.to_hdf('test_table_compress.hdf','test',mode='w',complib='blosc',format='table')
def test_hdf_table_read_compress():
pd.read_hdf('test_table_compress.hdf','test')
def test_csv_write(df):
df.to_csv('test.csv',mode='w')
def test_csv_read():
pd.read_csv('test.csv',index_col=0)