Google Sheets API и Pandas. Несогласованная длина данных из API - PullRequest
1 голос
/ 18 июня 2020

Я использую API листов Google для получения данных, которые затем передаю на Pandas, чтобы я мог легко работать с данными.

Допустим, я хочу получить лист со следующими данными ( изображен как объект JSON, поскольку таблицы здесь представлены не очень хорошо)

{
  columns: ['Name', 'Age', 'Tlf.' 'Address'],
  data: ['Julie', '35', '12345', '8 Leafy Street']
}

API листов вернет что-то вроде этого:

{
  'range': 'Cases!A1:AE999',
   'majorDimension': 'ROWS',
    'values': 
    [
            ['Name', 'Age', 'Tlf.', 'Address'],
      ['Julie', '35', '12345', '8 Leafy Street']
    ]
}

Это здорово и позволяет мне легко передавать заголовки столбцов и данные в Pandas без особых хлопот. Я делаю это следующим образом:

values = sheets_api_result["values"]
df = pd.DataFrame(values[1:], columns=values[0])
Моя проблема

Если у меня есть Gsuite Sheet, который выглядит, как в таблице ниже, обозначен как ключ: тип данных типа

{
  columns: ['Name', 'Age', 'Tlf.' 'Address'],
  data: ['Julie', '35', '', '']
}

I получит следующий ответ:

{
  'range': 'Cases!A1:AE999',
   'majorDimension': 'ROWS',
    'values': 
    [
            ['Name', 'Age', 'Tlf.', 'Address'],
      ['Julie', '35']
    ]
}

Обратите внимание, что длины двух массивов не равны, и что вместо возвращаемых значений None или null данные просто отсутствуют в ответе .

При работе с этими данными в моем коде я получаю ошибку, которая выглядит примерно так:

ValueError: 4 columns passed, passed data had 2 columns

Итак, насколько я могу судить, у меня есть два варианта:

  1. Придумайте умный способ дополнить мой ответ, где это необходимо, None
  2. Если возможно, проинструктируйте API вернуть нулевое значение в JSON, где существуют нулевые значения, особенно когда в последнем столбце (ах) вообще нет данных.

Что касается пункта 1. Я думаю, что могу добавить x None значений в список, где x равно length_of_column_heading_array - length_of_data_array. Однако это кажется уродливым, и, возможно, есть более элегантный способ сделать это.

Что касается пункта 2, мне не удалось найти ответ, который мне поможет.

Если у кого-нибудь есть идеи, как я могу это решить, я был бы очень благодарен.

Ура!

1 Ответ

0 голосов
/ 24 июня 2020

Если кому-то интересно, вот как я решил проблему.

Сначала нам нужно получить все данные из Sheets API.

# define the names of the tabs I want to get
ranges = ['tab1', 'tab2']

# Call the Sheets API
request = service.spreadsheets().values().batchGet(spreadsheetId=document, ranges=ranges,)
response = request.execute()

Теперь я хочу go через каждый столбец и убедитесь, что список каждой строки содержит такое же количество элементов, что и первая строка, содержащая заголовки столбцов.

# response is the response from google sheets API, 
# and from the code above. It contains column headings
# and data from every row.

# valueRanges is the key to access the data.
def extract_case_data(response, keyword):
    for obj in response["valueRanges"]:
        if keyword in obj["range"]:
            values = pad_data(obj["values"])
            df = pd.DataFrame(values[1:], columns=values[0])
            return df
    return None

И, наконец, метод заполнения данных

def pad_data(data: list):

    # build a new array with the column heading data
    # this is the list which we will return
    return_data = [data[0]]

    for row in data[1:]:
        difference = len(data[0]) - len(row)
        new_row = row
        # append None to the lists which have a shorter
        # length than the column heading list
        for count in range(1, difference + 1):
            new_row.append(None)
        return_data.append(new_row)
    return return_data

Я, конечно, не говорю, что это лучшее или самое элегантное решение, но оно помогло мне.

Надеюсь, это кому-то поможет.

...