更有效的方法跳过csv中的列到namedtuple函数?

2024-10-03 00:27:34 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在从彭博的开放符号学下载一个主数据表。csv有我不感兴趣的列。在

问题

有没有一种有效的/Pythonic方法可以从csv文件中找到的列的子集生成namedtuple实例?在

我尝试过的

我当前的流程(下面是Python 3.3代码)如下:

  1. 用csv中的所有列创建一个名为TempRecord的耦合。在
  2. 为csv文件中的每个记录创建TempRecord实例。在
  3. 从给定的TempRecord创建一个BSYMRecord(属性较少且已重命名)。在
  4. 生成BSYMRecord。在

这闻起来很低效。在

from csv import reader
from collections import namedtuple
from datetime import date
from io import BytesIO
from urllib.request import urlopen
from urllib.error import HTTPError
from zipfile import ZipFile


def bsym_records(sector, security_type, file_date):
    """Yield BSYMRecord for given sector and security type."""
    template = 'http://bdn-ak.bloomberg.com/precanned/{s}_{t}_{d}.txt.zip'
    url = template.format(s=sector, t=security_type, d=file_date)
    response = urlopen(url)
    zipfile = ZipFile(BytesIO(response.read()))
    for filename in zipfile.namelist():
        with zipfile.open(filename) as f:
            line = f.readline().decode('utf-8')
            headers = line.strip().replace(' ', '_').split('|')
            TempRecord = namedtuple('BSYMRecord', headers)
            while True:
                line = f.readline().decode('utf-8')
                if line[0] == '#':
                    break
                t = TempRecord._make(line.strip().split('|'))
                yield reduce_bsym_record(t)


BSYMRecord = namedtuple('BSYMRecord', ['name',
                                       'ticker',
                                       'pricing_source',
                                       'security_type',
                                       'market_sector',
                                       'BBGID',
                                       'BBGID_composite',
                                       'BSID',
                                       'unique_id'])


def reduce_bsym_record(record):
    """Eliminate non-essential fields."""
    return BSYMRecord._make((record.NAME,
                             record.ID_BB_SEC_NUM_DES,
                             record.FEED_SOURCE,
                             record.SECURITY_TYP,
                             record.MARKET_SECTOR_DES,
                             record.ID_BB_GLOBAL,
                             record.COMPOSITE_ID_BB_GLOBAL,
                             record.ID_BB_SEC_NUM_SRC,
                             record.ID_BB_UNIQUE))

Tags: csvfromimportiddatetypelinerecord
2条回答

您当前正在导入csv模块,但没有使用它。如果正在使用它,那么可以使用^{}类为文件中的每一行创建一个字典,而不是一个列表。可以使用关键字参数构造namedtuple,但它不会忽略伪参数。因此,您仍然需要手动筛选它们-但现在可以使用dict理解来完成此操作,而不是使用不同的namedtuple:

for line in csvfile:
    yield BSYMRecord(**{k:v for k,v in line if k in BSYMRecord._fieldnames})

诀窍是首先设置听写器。它需要一个生成字符串的类似文件的对象;ZipFile.open提供一个文件类对象,该对象产生字节,并且不能接受编码。codecs模块在这里起到了拯救作用-您可以获得一个StreamReader,它可以透明地将utf8字节解码为字符串,如下所示:

^{pr2}$

然后像这样使用它:

for filename in zipfile.namelist():
    with zipfile.open(filename) as f:
        csvfile = csv.DictReader(utf8(f))
        for line in csvfile:
             yield BSYMRecord(**{k:v for k,v in line if k in BSYMRecord._fieldnames})

您可以使用index根据标题从每行中选择所需的值:

fields = ["NAME", "ID_BB_SEC_NUM_DES", ...]

# ...                       
headers = line.strip().replace(' ', '_').split('|')
indices = [headers.index(field) for field in fields)
while True:
    # ...
    line = line.strip().split('|')
    yield BSYMRecord._make((line[i] for i in indices))

这使您的当前保护不受字段顺序的更改和所需字段的单一定义的影响,但这意味着您不必为每一行创建TempRecord。在

相关问题 更多 >