阅读表格#

大多数常见的ASCII表都可以用 read() 功能:

>>> from astropy.io import ascii
>>> data = ascii.read(table)  

在这里 table 是文件名、表的字符串表示形式或表行列表。返回值 (data 在这种情况下)是 Table 对象。

默认情况下, read() 将会尝试 guess the table format 通过尝试所有受支持的格式。

警告

对于大文件,猜测文件格式通常很慢,因为读者尝试用每种允许的格式解析文件,直到一种格式成功为止。对于大文件,建议禁用猜测 guess=False .

对于不能进行猜测的格式化异常的表格,请提供有关格式的其他提示::

>>> lines = ['objID                   & osrcid            & xsrcid       ',
...          '----------------------- & ----------------- & -------------',
...          '              277955213 & S000.7044P00.7513 & XS04861B6_005',
...          '              889974380 & S002.9051P14.7003 & XS03957B7_004']
>>> data = ascii.read(lines, data_start=2, delimiter='&')
>>> print(data)
  objID         osrcid          xsrcid
--------- ----------------- -------------
277955213 S000.7044P00.7513 XS04861B6_005
889974380 S002.9051P14.7003 XS03957B7_004

其他例子如下:

>>> data = astropy.io.ascii.read('data/nls1_stackinfo.dbout', data_start=2, delimiter='|')  
>>> data = astropy.io.ascii.read('data/simple.txt', quotechar="'")  
>>> data = astropy.io.ascii.read('data/simple4.txt', format='no_header', delimiter='|')  
>>> data = astropy.io.ascii.read('data/tab_and_space.txt', delimiter=r'\s')  

如果文件的格式是已知的(例如,它是固定宽度的表或IPAC表),则为 format 参数中的一个值 支持的格式 。例如::

>>> data = ascii.read(lines, format='fixed_width_two_line', delimiter='&')

请参阅 猜测表格式 部分,了解有关格式猜测的其他详细信息。

对于CSV等更简单的格式, read() 将自动尝试使用Cython/C解析引擎进行读取,这比普通Python实现(如中所述)快得多 快速ASCII I/O ). 如果快速引擎失灵, read() 默认情况下将依赖于Python阅读器。争论 fast_reader 可以指定来控制此行为。例如,要禁用快速引擎:

>>> data = ascii.read(lines, format='csv', fast_reader=False)

要阅读非常大的表格,请参阅 分块阅读大表 或使用 pandas (见下文注释)。

备注

通过指定包含纯字符的Python表来支持读取 encoding 参数。快速C阅读器不支持unicode。对于包含unicode的大数据文件,建议使用 pandas 并转换为 Table 通过 Table - Pandas interface .

这个 read() 函数接受许多指定详细表格式的参数。不同的格式可以定义不同的默认值,因此下面的描述有时会提到“典型的”默认值。这是指 Basic 格式读取器和其他类似的字符分隔格式。

参数用于 read()#

table输入表

有四种方法可以指定要读取的表:

  • 文件路径(字符串)

  • 包含由换行符分隔的所有表行的单个字符串

  • 具有可调用read()方法的类文件对象

  • 每个列表元素都是表行的字符串列表

前两个选项通过在字符串中出现新行来区分。这假设有效的文件名通常不包含换行符,有效的表输入至少包含两行。注意,一个表读入 no_header 格式可以合法地由一行组成;在这种情况下,将字符串作为带有单个项的列表传递将确保它不会被解释为文件名。

format文件格式(default='basic')

它指定ASCII表的顶层格式;例如,如果它是基本字符分隔表、固定格式表或CDS兼容表等。此参数的值必须是 支持的格式 .

guess尝试猜测表格格式(默认值=无)

如果设置为True,则 read() 将尝试通过循环许多可能的表格式置换来猜测表格式,并尝试在每种情况下读取表。见 Guess table format 有关详细信息,请参阅。

delimiter列分隔符字符串

用于分隔字段的单字符字符串,通常默认为空格字符。其他常用值可能是“\s”(空白)、“,”或“|”或“\t”(制表符)。值“\s”允许制表符和空格字符的任何组合来分隔列。

comment在表中定义注释行的正则表达式

如果 comment 正则表达式匹配表行的开头,则该行将从头或数据处理中丢弃。对于 basic 格式化默认为“\s*#”(后跟#的任何空白)。

quotechar一个字符串引用包含特殊字符的字段

它指定引号字符,通常是单引号或双引号字符。这对于读取以空格分隔的表中带有空格的文本字段非常有用。默认值通常是双引号。

header_start标题行的行索引

这只包括重要的非注释行,计数从0开始。如果设置为“无”,则表示没有标题行,列名将自动生成。看到了吗 Specifying header and data location 了解更多详细信息。

data_start开始数据计数的行索引

这只包括重要的非注释行,计数从0开始。看到了吗 Specifying header and data location 了解更多详细信息。

data_end数据结尾的行索引

这只包括重要的非注释行,从末尾开始计数可以是负数。看到了吗 Specifying header and data location 了解更多详细信息。

编码 :编码以读取文件 (default=None

什么时候? None 使用 locale.getpreferredencoding 作为一种编码。这与内置的默认行为相匹配 open 当没有的时候 mode 提供了参数。

convertersdict 指定输出数据类型DICT指定输出数据类型

请参阅 用于指定数据类型的转换器 一节中提供了示例。词典中的每个键都是一个列名,或者是包括通配符的名称匹配模式。该值为以下值之一:

  • Python数据类型或数字数据类型,如 intnp.float32

  • 此类类型的列表,将按顺序尝试,直到转换成功

  • 转换器元组列表(这并不常见,但请参阅 convert_numpy 函数作为示例)。

names每个数据列对应的名称列表

为每个数据列定义完整的名称列表。这将覆盖在标头中找到的名称(如果存在)。如果未提供,则使用标头中的名称,如果没有标头,则使用自动生成的名称。

include_names要包含在输出中的名称列表

从标题或 names 参数,选择此列表中仅输出列。如果未提供,则包括所有名称。

exclude_names要从输出中排除的名称列表

从输出列列表中排除这些名称。这是适用的 之后 这个 include_names 过滤。如果未指定,则不排除任何列。

fill_values填充值说明符列表

指定应在输出表中屏蔽的输入表项,因为这些项不正确或丢失。见 Bad or missing values 部分了解更多信息和示例。默认情况下,任何空白表值都将被视为丢失。

fill_include_names :受影响的列名列表 fill_values受影响的列名列表

这是一个列名列表(可以从标题或 names 参数)对于所有将填充值的列。 None (默认值)将适用 fill_values 到所有列。

fill_exclude_names :不受影响的列名列表 fill_values不受影响的列名列表

这是一个列名列表(可以从标题或 names 参数)的所有列 not 被填满。此参数的优先级高于 fill_include_names . 一个值 None (默认)不排除任何列。

outputter_cls输出级

这会将原始数据表值转换为由返回的输出对象 read() . 默认值为 TableOutputter ,返回 Table 对象(参见 Data Tables

inputter_cls输入程序类

一般不作规定。

data_splitter_cls :拆分数据列的拆分器类

header_splitter_cls :拆分标题列的拆分器类

fast_reader是否使用C引擎

这可以 TrueFalse ,同时也是 dict 有选择。(参见 快速ASCII I/O

读者 :读卡器类( 贬低 赞成 format读卡器类(

它指定ASCII表的顶级格式;例如,如果它是基本字符分隔表、固定格式表或CDS兼容表等,则此参数的值必须是Reader类。对于基本用法,这意味着内置 扩展读取器类 .

指定标头和数据位置#

三个参数 header_startdata_startdata_end 允许读取包含外部非表数据的表文件。在这种情况下你需要帮助 astropy.io.ascii 告诉它在哪里可以找到标题和数据。

当一个文件被处理成头和数据组件时,任何空行(可能有空格字符)和注释行(通常以注释字符开始 # )脱光 之前 头和数据解析代码查看表内容。

例子#

使用参数 header_startdata_startdata_end 要读取包含非表数据的表,请使用下面的文件。左侧的列不是文件的一部分,而是显示如何 astropy.io.ascii 正在查看每行和行计数索引。:

Index    Table content
------ ----------------------------------------------------------------
   -  | # This is the start of my data file
   -  |
   0  | Automatically generated by my_script.py at 2012-01-01T12:13:14
   1  | Run parameters: None
   2  | Column header line:
   -  |
   3  | x y z
   -  |
   4  | Data values section:
   -  |
   5  | 1 2 3
   6  | 4 5 6
   -  |
   7  | Run completed at 2012:01-01T12:14:01

在这种情况下你会 header_start=3data_start=5data_end=7 . 公约 data_end 遵循常规的Python切片约定,在哪里选择数据行5和6 rows[5:7] . 为了 data_end 您也可以提供一个负索引从末尾倒数,因此 data_end=-1 (像 rows[5:-1] )在这种情况下是可行的。

错误或缺少值#

ASCII数据表可能包含错误或丢失的值。一种常见的情况是,表包含没有可用数据的空白条目。

实例#

以一个表为例,表中的条目为空:

>>> weather_data = """
...   day,precip,type
...   Mon,1.5,rain
...   Tues,,
...   Wed,1.1,snow
...   """

默认情况下, read() 将把空白条目解释为错误/缺失,并通过将相应的掩码值设置为,输出一个屏蔽表,其中这些条目被屏蔽 True ::

>>> dat = ascii.read(weather_data)
>>> print(dat)
day  precip type
---- ------ ----
 Mon    1.5 rain
Tues     --   --
 Wed    1.1 snow

如果要用特定值替换遮罩(缺少)值,请设置遮罩列 fill_value 属性,然后获取表的“已填充”版本。如下所示:

>>> dat['precip'].fill_value = -999
>>> dat['type'].fill_value = 'N/A'
>>> print(dat.filled())
day  precip type
---- ------ ----
 Mon    1.5 rain
Tues -999.0  N/A
 Wed    1.1 snow

ASCII表也可能有其他错误或丢失数据的指示器。例如,一个表可能包含不是数字的有效表示形式的字符串值(例如。, "..." ),或者表可能具有特殊值,例如 -999 它们被选中来指示丢失的数据。这个 read() 函数有一个灵活的系统,通过在转换过程中将输入数据中的指定字符序列标记为“缺失数据”,以适应这些情况。一旦发现丢失的数据,输出将是一个屏蔽表。

这是用 fill_values 关键字参数,可以设置为单个缺少值规范 <missing_spec> 或一览表 <missing_spec> 元组::

fill_values = <missing_spec> | [<missing_spec1>, <missing_spec2>, ...]
<missing_spec> = (<match_string>, '0', <optional col name 1>, <optional col name 2>, ...)

当读取表时 <missing_spec> 应该总是字符串 '0' ,否则可能会出现意外行为 [1]. 默认情况下, <missing_spec> 应用于所有列,除非提供了列名字符串。另一种限制列的方法是通过 fill_include_namesfill_exclude_names 中的关键字参数 read() .

在下面的示例中,我们在用典型的占位符填充缺少的值之后,读回天气表:

>>> table = ['day   precip  type',
...          ' Mon     1.5  rain',
...          'Tues  -999.0   N/A',
...          ' Wed     1.1  snow']
>>> t = ascii.read(table, fill_values=[('-999.0', '0', 'precip'), ('N/A', '0', 'type')])
>>> print(t)
day  precip type
---- ------ ----
 Mon    1.5 rain
Tues     --   --
 Wed    1.1 snow

备注

默认值 read()fill_values=('','0') . 这会将任何数据类型(int、float或string)的空白条目标记为缺失。如果 fill_values 在调用中显式设置 read() 然后,将空白条目标记为缺少的默认行为将不再适用。例如设置实例 fill_values=None 将禁用此自动遮罩,而不设置任何其他填充值。这对于字符串列很有用,其中一个值恰好是 "" .

选择要遮罩的列#

这个 read() 函数提供参数 fill_include_namesfill_exclude_names 选择将在 fill_values 上述掩蔽过程。

使用这些参数并不常见,但在某些情况下,可以大大简化读取表所需的代码。下面给出一个简单的例子来说明 fill_include_namesfill_exclude_names 可用于最基本和最典型的情况:

>>> from astropy.io import ascii
>>> lines = ['a,b,c,d', '1.0,2.0,3.0,4.0', ',,,']
>>> ascii.read(lines)
<Table length=2>
   a       b       c       d
float64 float64 float64 float64
------- ------- ------- -------
    1.0     2.0     3.0     4.0
     --      --      --      --

>>> ascii.read(lines, fill_include_names=['a', 'c'])
<Table length=2>
   a     b      c     d
float64 str3 float64 str3
------- ---- ------- ----
    1.0  2.0     3.0  4.0
     --           --

>>> ascii.read(lines, fill_exclude_names=['a', 'c'])
<Table length=2>
 a      b     c      d
str3 float64 str3 float64
---- ------- ---- -------
 1.0     2.0  3.0     4.0
          --           --

猜测表格式#

如果 guess 中的参数 read() 设置为True,则 read() 将尝试通过循环遍历许多可能的表格式排列并尝试在每种情况下读取表来猜测表格式。成功的第一种格式将用于读取表。若要成功,读取器必须成功解析该表,并满足以下列要求:

  • 至少两个表列。

  • 列名不是浮点数或整数。

  • 列名不能以空格、逗号、制表符、单引号、双引号或竖线(|)开头或结尾。

这些要求减少了使用错误格式成功解析表时出现误报的可能性。一种常见的情况是,表中有数值列,但没有标题行,在这种情况下 astropy.io.ascii 将自动分配列名,因为列名看起来像数字。

猜测顺序#

猜测的顺序如下所示:

for format in ("ecsv", "fixed_width_two_line", "rst", "fast_basic", "basic",
               "fast_rdb", "rdb", "fast_tab", "tab", "cds", "daophot", "sextractor",
               "ipac", "latex", "aastex"):
    read(format=format)

for format in ("commented_header", "fast_basic", "basic", "fast_noheader", ""noheader"):
    for delimiter in ("|", ",", " ", "\\s"):
        for quotechar in ('"', "'"):
            read(format=format, delimiter=delimiter, quotechar=quotechar)

请注意 FixedWidth 派生读取器不包括在默认猜测序列中(这会导致问题),因此要读取此类表,必须使用 format 关键字。还请注意,与快速读取引擎兼容的格式尝试在普通读取引擎之前使用快速引擎。

如果没有一个猜测成功地读取了表(取决于列的要求),则只使用用户提供的参数进行最后一次尝试,但不检查列需求。这样,只有一个或多个列名看起来像数字的表仍然可以被成功读取。

猜测过程遵循格式、分隔符和报价计算参数的任何值,以及提供给Read()函数的快速阅读器选项。任何可能会冲突的猜测都会被跳过。例如,调用::

>>> data = ascii.read(table, format="no_header", quotechar="'")

将只尝试四种可能的分隔符,跳过所有冲突的格式和引号组合。类似地,对于任何设置 fast_reader 这需要使用FAST引擎,只会尝试上面格式列表中的FAST变体。

停用#

猜测可以通过两种方式禁用:

import astropy.io.ascii
data = astropy.io.ascii.read(table)               # guessing enabled by default
data = astropy.io.ascii.read(table, guess=False)  # disable for this call
astropy.io.ascii.set_guess(False)                 # set default to False globally
data = astropy.io.ascii.read(table)               # guessing disabled

调试#

为了更深入地了解猜测过程,并可能在某些东西未按预期工作时进行调试,请使用 get_read_trace() 功能。这将返回上一次调用的尝试读取格式的回溯 read() .

注释和元数据#

读取期间检测到的任何注释行都将通过 comments 把桌子的钥匙 .meta 字典。

例子#

读取过程中检测到的注释行插入到输出表中,如下所示:

>>> table='''# TELESCOPE = 30 inch
...          # TARGET = PV Ceph
...          # BAND = V
...          MJD mag
...          55555 12.3
...          55556 12.4'''
>>> dat = ascii.read(table)
>>> print(dat.meta['comments'])
['TELESCOPE = 30 inch', 'TARGET = PV Ceph', 'BAND = V']

同时 astropy.io.ascii 不会对注释行执行任何后处理,自定义后处理可以通过重新读取元数据行注释来完成。下面是一个示例,其中注释的形式为“#KEY=VALUE”::

>>> header = ascii.read(dat.meta['comments'], delimiter='=',
...                     format='no_header', names=['key', 'val'])
>>> print(header)
   key      val
--------- -------
TELESCOPE 30 inch
   TARGET PV Ceph
     BAND       V

用于指定数据类型的转换器#

astropy.io.ascii 使用转换器函数(如Python)将表中的原始字符串值转换为数值数据类型 intfloat 函数或数字数据类型,如 np.float64

默认转换器为:

default_converters = [int, float, str]

可以用重写每个列的默认转换器 converters 关键词:

>>> import numpy as np
>>> converters = {'col1': np.uint,
...               'col2': np.float32}
>>> ascii.read('file.dat', converters=converters)  

除了单个列名之外,您还可以通过 fnmatch 若要选择多列,请执行以下操作。例如,我们可以将名称以“ol”开头的所有列的格式设置为无符号整数,同时将默认转换器应用于表中的所有其他列::

>>> import numpy as np
>>> converters = {'col*': np.uint}
>>> ascii.read('file.dat', converters=converters)  

转换器中的值 dict 也可以是类型列表,在这种情况下,将按顺序尝试这些类型。这允许灵活的类型转换。例如,假设您读到了下表:

>>> txt = """\
...   a   b    c
... --- --- -----
...   1 3.5  True
...   2 4.0 False"""
>>> t = ascii.read(txt, format='fixed_width_two_line')

默认情况下, TrueFalse 值将被解释为字符串。但是,如果希望将这些值读取为布尔值,则可以执行以下操作:

>>> converters = {'*': [int, float, bool, str]}
>>> t = ascii.read(txt, format='fixed_width_two_line', converters=converters)
>>> print(t['c'].dtype)
bool

高级用法#

在内部,类型转换使用 convert_numpy() 返回两个元素的元组的函数 (converter_func, converter_type) 。此双元素元组可用作 converters 迪克特。提供给 convert_numpy() 必须是有效的 NumPy type 比如 numpy.intnumpy.uintnumpy.int8numpy.int64numpy.floatnumpy.float64 ,或 numpy.str

也可以直接将任意转换函数作为 converter_func 两元素元组的元素。

Fortran风格指数#

这个 fast converter C输入解析器提供了一个 exponent_style 用于定义自定义字符而不是标准字符的选项 'e' 对于输入文件中的指数格式,例如,读取Fortran格式的双精度数字,例如 '1.495978707D+13'

>>> ascii.read('double.dat', format='basic', guess=False,
...            fast_reader={'exponent_style': 'D'})  

特殊设置 'fortran' 允许自动检测任何有效的Fortran指数字符 ('E''D''Q' ),以及没有任何字符前缀的三位数指数(例如。, '2.1127123261674622-107' ). 输入数据中的所有值和指数字符都不区分大小写;默认值以外的任何值 'E' 表示自动设置 'use_fast_converter': True .

高级定制#

在这里,我们提供了一些基本的例子来说明如何扩展基本的功能。要超越这些示例,最好的参考是阅读现有的代码 扩展读取器类 .

实例#

对于特殊情况,这些示例演示了如何扩展的基本功能 astropy.io.ascii .

通过类继承定义自定义读取器

定义新的reader类最有用的方法是通过继承。所有的内置读取器都是这样定义的,所以代码中有很多示例。

在大多数情况下,您将定义一个类来处理头、一个处理数据的类和一个将所有数据绑定在一起的reader类。下面是代码中的一个示例,它定义了一个与基本读取器类似的读取器,但头和数据以文件的不同行开始:

# Note: NoHeader is already included in astropy.io.ascii for convenience.
class NoHeaderHeader(BasicHeader):
    """Reader for table header without a header

    Set the start of header line number to `None`, which tells the basic
    reader there is no header line.
    """
    start_line = None

class NoHeaderData(BasicData):
    """Reader for table data without a header

    Data starts at first uncommented line since there is no header line.
    """
    start_line = 0

class NoHeader(Basic):
    """Read a table with no header line.  Columns are autonamed using
    header.auto_format which defaults to "col%d".  Otherwise this reader
    the same as the :class:`Basic` class from which it is derived.  Example::

      # Table data
      1 2 "hello there"
      3 4 world
    """
    _format_name = 'no_header'
    _description = 'Basic table with no headers'
    header_class = NoHeaderHeader
    data_class = NoHeaderData

在更复杂的情况下,实现还可以重写基类中的某些方法:

# Note: CommentedHeader is already included in astropy.io.ascii for convenience.
class CommentedHeaderHeader(BasicHeader):
    """Header class for which the column definition line starts with the
    comment character.  See the :class:`CommentedHeader` class  for an example.
    """
    def process_lines(self, lines):
        """Return only lines that start with the comment regexp.  For these
        lines strip out the matching characters."""
        re_comment = re.compile(self.comment)
        for line in lines:
            match = re_comment.match(line)
            if match:
                yield line[match.end():]

    def write(self, lines):
        lines.append(self.write_comment + self.splitter.join(self.colnames))


class CommentedHeader(Basic):
    """Read a file where the column names are given in a line that begins with
    the header comment character. ``header_start`` can be used to specify the
    line index of column names, and it can be a negative index (for example -1
    for the last commented line).  The default delimiter is the <space>
    character.::

      # col1 col2 col3
      # Comment line
      1 2 3
      4 5 6
    """
    _format_name = 'commented_header'
    _description = 'Column names in a commented line'

    header_class = CommentedHeaderHeader
    data_class = NoHeaderData

从功能上定义自定义读取器

不需要定义新类,还可以获取读取器的实例,然后在函数中修改该读取器实例的属性:

def read_rdb_table(table):
    reader = astropy.io.ascii.Basic()
    reader.header.splitter.delimiter = '\t'
    reader.data.splitter.delimiter = '\t'
    reader.header.splitter.process_line = None
    reader.data.splitter.process_line = None
    reader.data.start_line = 2

    return reader.read(table)

Create a custom splitter.process_val function ::

# The default process_val() normally just strips whitespace.
# In addition have it replace empty fields with -999.
def process_val(x):
    """Custom splitter process_val function: Remove whitespace at the beginning
    or end of value and substitute -999 for any blank entries."""
    x = x.strip()
    if x == '':
        x = '-999'
    return x

# Create an RDB reader and override the splitter.process_val function
rdb_reader = astropy.io.ascii.get_reader(reader_cls=astropy.io.ascii.Rdb)
rdb_reader.data.splitter.process_val = process_val

分块阅读大表#

读取ASCII表的默认过程不具有内存效率,并且可能暂时需要比文件大小大得多的内存(最多为5到10倍)。在临时内存需求超过可用内存的情况下,当使用磁盘缓存时,这可能会导致显著的减速。

在这种情况下,有一种方法可以将表分成大小有限的小块来读取。有两种可能的方法:

  • 分块阅读表格,并在此过程中汇总最终表格。这只需要比最终表所需的内存多一点。

  • 使用Python生成器函数返回 Table 输入表的每个块的对象。这允许扫描任意大的表,因为它从不返回最终的聚合表。

块读取功能对于非常大的表非常有用,因此这仅适用于 快速ASCII I/O 读者。支持以下格式: tabcsvno_headerrdbbasic . 这个 commented_header 不支持直接读取格式,但不支持直接读取 no_header 使用 names 争论。

为了分块读取表,必须提供 fast_reader 关键字参数 dict 包括 chunk_size 键,其值为要读取的输入表的每个块的大致大小(以字节为单位)。此外,如果您提供 chunk_generator 设置为的键 True ,然后返回一个迭代器,为输入的每个块提供一个表,而不是为整个输入返回一个表。

实例#

要在限制内存使用峰值时读取整个表:::

# Read a large CSV table in 100 Mb chunks.

tbl = ascii.read('large_table.csv', format='csv', guess=False,
                 fast_reader={'chunk_size': 100 * 1000000})

要使用迭代器分块读取表,我们遍历一个CSV表并选择 Vmag 列小于8.0(例如,表中所有恒星的亮度都大于8.0 mag)。我们收集所有这些子表,然后将它们堆叠在最后。:

from astropy.table import vstack

# tbls is an iterator over the chunks (no actual reading done yet)
tbls = ascii.read('large_table.csv', format='csv', guess=False,
                  fast_reader={'chunk_size': 100 * 1000000,
                               'chunk_generator': True})

out_tbls = []

# At this point the file is actually read in chunks.
for tbl in tbls:
    bright = tbl['Vmag'] < 8.0
    if np.count_nonzero(bright):
        out_tbls.append(tbl[bright])

out_tbl = vstack(out_tbls)

备注

Performance

指定 format 显式地使用 guess=False 对于大桌子来说是个好主意。这可以防止在格式已知的典型情况下进行不必要的猜测。

这个 chunk_size 通常应设置为给定可用系统内存的合理最大值。处理每个块都有开销,因此块越少越好。

如何查找和解决阅读表格中的问题#

本节的目的是提供几个示例,说明如何处理无法读取的表。

获取不同格式的数据表#

有时,以更结构化的格式更清楚地定义列和元数据很容易获得数据,例如FITS或VO/XML表,或使用不同列分隔符(例如,逗号而不是空格)或固定宽度列的ASCII表。在这种情况下,最快的解决方案可能是简单地下载或以不同的格式再次导出数据。

找到问题所在#

通常, astropy.io.ascii.read 尝试许多不同的格式,直到一个人阅读成功。如果它奏效了,你就不必再为阅读寻找和设置正确的选项了。但是,如果它找不到正确解析文件的格式和格式选项的任何组合,则会收到一条很长的异常消息,其中显示尝试过的每种格式,并以以下建议结束:

************************************************************************
** ERROR: Unable to guess table format with the guesses listed above. **
**                                                                    **
** To figure out why the table did not read, use guess=False and      **
** fast_reader=False, along with any appropriate arguments to read(). **
** In particular specify the format and any known attributes like the **
** delimiter.                                                         **
************************************************************************

为了进一步说明这一点,您可能通过查看该文件就知道它是什么格式的,这一定是 支持的格式 。例如,它可能是一个基本的空格分隔文件,但具有标题行作为如下所示的注释,这对应于 commented_header 格式::

>>> table = """# name id
... Jill 1232
... Jack Johnson 456"""

为了找出读取此文件的实际问题,您需要执行以下操作:

>>> ascii.read(table, format='commented_header', delimiter=' ', guess=False, fast_reader=False)
Traceback (most recent call last):
  ...
astropy.io.ascii.core.InconsistentTableError: Number of header columns (2) inconsistent with data columns (3) at data line 1
Header values: ['name', 'id']
Data values: ['Jack', 'Johnson', '456']

在这一点上,您可以看到问题在于第二个数据行有3列,而标题显示应该只有2列。 data line 1 因为问题在文件的第三行。这里发生了两件事。第一, data line 1 指数据行数,不包括任何标题行、空行或注释掉的行。第二,计数从零开始,因此 1 是第二条数据线。请参阅 猜测表格式 部分,了解有关格式猜测的其他详细信息。

使表格更易于阅读#

有时,参数 astropy.io.ascii.read 例如,指定 formatdelimitercommentquote_charheader_startdata_startdata_end ,以及 encoding 是不够的。若要仅读取格式接近但不完全相同的单个表 支持的格式 ,最快的解决方案可能是在文本编辑器中打开该表文件,对其进行修改,直到它符合可读取的格式。另一方面,如果我们需要一次又一次地读取该特定格式的表,最好是找到一种方法来读取它们 ascii 无需手动修改每个文件。

标题行的格式不正确#

下表将无法解析(引发 InconsistentTableError ),因为标题行看起来有三列,而实际上只有两列::

Name spectral type
Vega A0
Altair A7

在文本编辑器中打开此文件以修复格式很容易::

Name "spectral type"
Vega A0
Altair A7

或:

Name spectral_type
Vega A0
Altair A7

使用上述任何一项更改,您都可以使用默认设置读取文件。

要在不编辑文件的情况下读取表,我们需要忽略格式错误的标题行,并自己传递列名。在不修改表文件的情况下,通过设置 data_start 参数::

>>> table = """
... Star spectral type
... Vega A0
... Altair A7
... """
>>> ascii.read(table, names=["Star", "spectral type"], data_start=1)
<Table length=2>
 Star  spectral type
 str6       str2
------ -------------
  Vega            A0
Altair            A7

格式错误的数据行#

类似的原则也适用于格式不佳的数据行。以下是列数不一致的表 (alpha Cen 应该写成 "alpha Cen" 明确“阿尔法”和“Cen”这两个词是同一栏的一部分):

Star SpT
Vega A0
alpha Cen G2V+K1

当我们试图用来阅读的时候 guess=False ,Astopy抛出了一个 astropy.io.ascii.InconsistentTableError **

>>> from astropy.io import ascii
>>> table = '''
... Star SpT
... Vega A0
... alpha Cen G2V+K1
... '''
>>> ascii.read(table, guess=False)
Traceback (most recent call last):
    ...
astropy.io.ascii.core.InconsistentTableError: Number of header columns (2) inconsistent with data columns in data line 1

这将我们带到有问题的行,这里是行1(像在Python中一样,在标题行之后开始计数,并从0开始计数数据行)。在这个只有两行的表中,这个问题很容易发现,但是对于较长的表,行号非常有用。现在,我们可以通过在文件中添加引号来手动修复该行 "alpha Cen" 。然后,我们可以尝试再次读取表,看看它是否正常工作,或者是否存在另一个格式错误的数据行。

读取Gaia数据表#

备注

推荐的访问盖亚的方式是通过其 astroquery.gaia 模块。但是,如果您需要通过以下方式单独访问其数据文件 astropy ,然后继续阅读。

中提供了GAIA数据表 ECSV 格式,包括表和列的详细元数据(例如,列描述、单位和数据类型)。例如,DR3表格在http://cdn.gea.esac.esa.int/Gaia/gdr3/gaia_source/.

DR3数据文件不严格符合ECSV标准,因为它们使用标记 null 来指示缺少的值,而不是必需的 "" 。为了使用完整的元数据正确读取这些文件,我们需要告诉ECSV阅读器 null 作为缺少的值::

>>> from astropy.table import QTable
>>> dat = QTable.read(
...     "GaiaSource_000000-003111.csv.gz",
...     format="ascii.ecsv",
...     fill_values=("null", "0")
... )