Транспонировать матрицу n * 3 в матрицу n * m

#python #python-3.x

#python #python-3.x

Вопрос:

Для веб-сервера я пытаюсь сгенерировать отчет с указанием количества запросов с различными кодами ответов в течение некоторой фиксированной продолжительности, скажем, часа.

Из необработанных данных журналов http-доступа я сначала сгенерировал массив array, где каждая строка содержит 3 ячейки: час, код ответа и количество запросов. Из этого я затем генерирую конечный результат. Логика довольно проста, для каждой строки во входных данных,

У меня это работает, см. Небольшой пример, но он не кажется «питоническим», мне интересно, есть ли лучший способ сделать это. У меня есть начальные навыки в Python, и я не знаком с различными библиотеками обработки данных.

Есть ли лучший способ сделать это? Существуют ли какие-либо библиотеки, которые можно использовать для непосредственного получения конечного результата из исходных необработанных данных?

Кроме того, я почти уверен, что transpose — неправильное название для этого преобразования, буду признателен, если кто-нибудь сможет меня поправить и в этом.

 #! /usr/bin/python3

'''
data is an array of array n*3:
h  resp  count
1   200     15
1   201     23
2   200      9
2   201     75
2   404      5

result is an array of n*m:
   200  202   404
1   15   23     0
2    9   75     5
'''

def process(data):
  result = [[None]]
  for inrow in data:
    r,c,v = inrow[0], inrow[1], inrow[2]
    row = find_row(result, r)
    idx = find_column_index(result, c)
    row[idx] = v
  return result

def find_row(result, r):
  row = next((row for row in result[1:] if row[0] == r), None)
  if not row:
    row = [r]
    result.append(row)
    for x in result[0][1:]:
      row.append(0)
  return row

def find_column_index(result, c):
  columns = result[0]
  idx = next((idx for idx in range(len(columns)) if columns[idx] == c), None)
  if not idx:
    columns.append(c)
    for row in result[1:]:
      row.append(0)
    idx = len(columns) - 1
  return idx

def test():
  #import pdb; pdb.set_trace()
  arr = [
    [1, "200", 15],
    [1, "202", 23],
    [2, "200", 9],
    [2, "202", 75],
    [2, "404", 5]
    ]
  result = process(arr)
  print(result)

if __name__ == "__main__":
  test()

 

Комментарии:

1. Здравствуйте, меня смущает ваше описание ваших входных данных и выходных данных: я предполагаю, что ваш пример ввода и вывода данных написан неправильно в ваших комментариях. Вы хотели, чтобы ваш результат составлял часы в зависимости от типа запроса? т.е. (hr 1 соответствует 202 «200» ответам, 23 «201» ответам и 0 «404» ответам; hr 2 соответствует 9 «200» ответам, 75 «201» ответам и так далее?

2. @pooh17yes в первой строке последний столбец неверен в комментариях, он верен в тестовых данных внизу. Сейчас я отредактирую свой пост. И вы правы в отношении выходных данных — количество запросов в каждый час для различных кодов ответов

Ответ №1:

Pandas может решить это легко для вас, просто перенесите фрейм данных в сводную таблицу:

 import pandas as pd
df = pd.DataFrame(arr = [
    [1, "200", 15],
    [1, "202", 23],
    [2, "200", 9],
    [2, "202", 75],
    [2, "404", 5]
    ],columns = ['h', 'resp', 'count'])
pivot = df.pivot(values='count',index='h',columns='resp')
print(pivot)
 

Комментарии:

1. Это потрясающе. Возможно ли также сгенерировать конечный результат из необработанных данных, которые представляют собой массив (timestamp, response-code) ? Мне нужно было бы извлечь час (или вычислить какой-то другой период) и получить их количество

2. Наконец-то удалось приступить pandas к работе cygwin . Кажется, что должна быть небольшая ошибка выше df.pivot(values='count',index='h',columns='count') df.pivot(values='count',index='h',columns='resp') . Я подожду день или два, прежде чем редактировать ваш ответ. Также отображаются отсутствующие значения, NaN которыми я хотел бы быть 0 . Я добавлю еще один комментарий и отредактирую, как только выясню, как это сделать