Как распечатать выровненный массив с текстовыми метками строк и столбцов? - PullRequest
9 голосов
/ 19 февраля 2011

Есть ли какой-нибудь элегантный способ использовать правильную особенность интервала в print numpy.array для получения двумерного массива с правильными метками, который выравнивается правильно? Например, учитывая массив с 4 строками и 5 столбцами, как я могу предоставить массив и списки соответствующего размера, соответствующие столбцам строки и заголовка, для генерации некоторого вывода, который выглядит следующим образом?

      A   B   C   D   E
Z [[ 85  86  87  88  89]
Y  [ 90 191 192  93  94]
X  [ 95  96  97  98  99]
W  [100 101 102 103 104]]

Если я наивно попробую:

import numpy
x = numpy.array([[85, 86, 87, 88, 89], \
                 [90, 191, 192, 93, 94], \
                 [95, 96, 97, 98, 99], \
                 [100,101,102,103,104]])

row_labels = ['Z', 'Y', 'X', 'W']


print "     A   B   C   D   E"
for row, row_index in enumerate(x):
    print row_labels[row_index], row

Я получаю:

      A   B   C   D   E
Z  [85  86  87  88  89]
Y  [90 191 192  93  94]
X  [95  96  97  98  99]
W  [100 101 102 103 104]

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

Ответы [ 4 ]

11 голосов
/ 02 января 2014

Для этого вы можете использовать IPython notebook + Pandas .Введите свой оригинальный пример в блокнот IPython:

import numpy
x = numpy.array([[85, 86, 87, 88, 89], 
                 [90, 191, 192, 93, 94], 
                 [95, 96, 97, 98, 99], 
                 [100,101,102,103,104]])

row_labels = ['Z', 'Y', 'X', 'W']
column_labels = ['A', 'B', 'C', 'D', 'E']

Затем создайте DataFrame:

import pandas
df = pandas.DataFrame(x, columns=column_labels, index=row_labels)

И затем просмотрите его:

enter image description here

10 голосов
/ 19 февраля 2011

Предполагая, что все номера матриц имеют не более 3 цифр, вы можете заменить последнюю часть следующим образом:

print "     A   B   C   D   E"
for row_label, row in zip(row_labels, x):
    print '%s [%s]' % (row_label, ' '.join('%03s' % i for i in row))

Что выводит:

     A   B   C   D   E
Z [ 85  86  87  88  89]
Y [ 90 191 192  93  94]
X [ 95  96  97  98  99]
W [100 101 102 103 104]

Форматирование с '%03s' приводитстрока длиной 3 с левым отступом (с использованием пробелов).Используйте '%04s' для длины 4 и так далее.Полный синтаксис строки формата описан в документации Python.

6 голосов
/ 19 февраля 2011

Вот способ использовать функции печати массива. Я, вероятно, не буду использовать его, но он достаточно близок к удовлетворению ваших требований!

a = np.random.rand(5,4)
x = np.array('col1 col2 col3 col4'.split())
y = np.array('row1 row2 row3 row4 row5'.split())
b = numpy.zeros((6,5),object)
b[1:,1:]=a
b[0,1:]=x
b[1:,0]=y
b[0,0]=''
printer = np.vectorize(lambda x:'{0:5}'.format(x,))
print printer(b).astype(object)

[[     col1 col2 col3 col4]
 [row1 0.95 0.71 0.03 0.56]
 [row2 0.56 0.46 0.35 0.90]
 [row3 0.24 0.08 0.29 0.40]
 [row4 0.90 0.44 0.69 0.48]
 [row5 0.27 0.10 0.62 0.04]]
0 голосов
/ 31 августа 2014

Этот код, по сути, является реализацией вышеприведенного scoffey, но он не имеет трехсимвольного ограничения и немного более мощный.Вот мой код:

    def format__1(digits,num):
        if digits<len(str(num)):
            raise Exception("digits<len(str(num))")
        return ' '*(digits-len(str(num))) + str(num)
    def printmat(arr,row_labels=[], col_labels=[]): #print a 2d numpy array (maybe) or nested list
        max_chars = max([len(str(item)) for item in flattenList(arr)+col_labels]) #the maximum number of chars required to display any item in list
        if row_labels==[] and col_labels==[]:
            for row in arr:
                print '[%s]' %(' '.join(format__1(max_chars,i) for i in row))
        elif row_labels!=[] and col_labels!=[]:
            rw = max([len(str(item)) for item in row_labels]) #max char width of row__labels
            print '%s %s' % (' '*(rw+1), ' '.join(format__1(max_chars,i) for i in col_labels))
            for row_label, row in zip(row_labels, arr):
                print '%s [%s]' % (format__1(rw,row_label), ' '.join(format__1(max_chars,i) for i in row))
        else:
            raise Exception("This case is not implemented...either both row_labels and col_labels must be given or neither.")

выполняется

    import numpy
    x = numpy.array([[85, 86, 87, 88, 89],
                     [90, 191, 192, 93, 94],
                     [95, 96, 97, 98, 99],
                     [100,101,102,103,104]])
    row_labels = ['Z', 'Y', 'X', 'W']
    column_labels = ['A', 'B', 'C', 'D', 'E']
    printmat(x,row_labels=row_labels, col_labels=column_labels)

дает

         A   B   C   D   E
    Z [ 85  86  87  88  89]
    Y [ 90 191 192  93  94]
    X [ 95  96  97  98  99]
    W [100 101 102 103 104]

Это также будет вывод, если вместо 'x' будет просто вложенный список питоновмассива numpy.

...