#python-3.x #pandas #csv
Вопрос:
Я пытаюсь прочитать данные из https://download.bls.gov/pub/time.series/bp/bp.measure используя панд, вот так:
import pandas as pd
url = 'https://download.bls.gov/pub/time.series/bp/bp.measure'
df = pd.read_csv(url, sep='t')
Однако мне просто нужно получить набор данных с двумя столбцами: measure_code
и measure_text
. Поскольку этот набор данных в качестве заголовка BP measure
я также попытался прочитать его так:
url = 'https://download.bls.gov/pub/time.series/bp/bp.measure'
df = pd.read_csv(url, sep='t', skiprows=1)
Но в этом случае он возвращает набор данных только с одним столбцом, и я не могу его пропустить:
>>> df.columns
Index([' measure_code measure_text'], dtype='object')
Есть какие-либо предложения/идеи о лучшем подходе к получению этого набора данных?
Ответ №1:
Это, безусловно, возможно, но формат имеет несколько причуд.
- Как вы заметили, заголовки столбцов начинаются со строки 2, поэтому вам нужно
skiprows=1
. - Файл разделен пробелом, а не разделен вкладками.
- Значения столбцов продолжаются через несколько строк.
Проблемы 1 и 2 можно исправить с помощью skiprows
и sep
. Задача 3 сложнее и требует небольшой предварительной обработки файла. По этой причине я использовал немного более гибкий способ извлечения файла, используя библиотеку запросов. Как только у меня есть файл, я использую регулярные выражения, чтобы исправить проблему 3, и возвращаю файл пандам.
Вот код:
import requests
import re
import io
import pandas as pd
url = 'https://download.bls.gov/pub/time.series/bp/bp.measure'
# Get the URL, convert the document from DOS to Unix linebreaks
measure_codes = requests.get(url)
.text
.replace("rn", "n")
# If there's a linebreak, followed by at least 7 spaces, combine it with
# previous line
measure_codes = re.sub("n {7,}", " ", measure_codes)
# Convert the string to a file-like object
measure_codes = io.BytesIO(measure_codes.encode('utf-8'))
# Read in file, interpreting 4 spaces or more as a delimiter.
# Using a regex like this requires using the slower Python engine.
# Use skiprows=1 to skip the header
# Use dtype="str" to avoid converting measure code to integer.
df = pd.read_csv(measure_codes, engine="python", sep=" {4,}", skiprows=1, dtype="str")
print(df)