Чтение CSV с помощью панд

#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:

Это, безусловно, возможно, но формат имеет несколько причуд.

  1. Как вы заметили, заголовки столбцов начинаются со строки 2, поэтому вам нужно skiprows=1 .
  2. Файл разделен пробелом, а не разделен вкладками.
  3. Значения столбцов продолжаются через несколько строк.

Проблемы 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)