web-dev-qa-db-fra.com

Ajouter des en-têtes de ligne / colonne aux tableaux NumPy

J'ai un NumPyndarray auquel j'aimerais ajouter des en-têtes de ligne/colonne.

Les données sont en fait 7x12x12, mais je peux les représenter comme ceci:

  A=[[[0, 1, 2, 3, 4, 5],
      [1, 0, 3, 4, 5, 6],
      [2, 3, 0, 5, 6, 7],
      [3, 4, 5, 0, 7, 8],
      [4, 5, 6, 7, 0, 9],
      [5, 6, 7, 8, 9, 0]]


     [[0, 1, 2, 3, 4, 5],
      [1, 0, 3, 4, 5, 6],
      [2, 3, 0, 5, 6, 7],
      [3, 4, 5, 0, 7, 8],
      [4, 5, 6, 7, 0, 9],
      [5, 6, 7, 8, 9, 0]]]

où A est ma matrice 2x6x6.

Comment insérer des en-têtes sur la première ligne et la première colonne, de sorte que chaque tableau ressemble à ceci dans mon fichier de sortie CSV?

        A, a, b, c, d, e, f 
        a, 0, 1, 2, 3, 4, 5,
        b, 1, 0, 3, 4, 5, 6,
        c, 2, 3, 0, 5, 6, 7,
        d, 3, 4, 5, 0, 7, 8,
        e, 4, 5, 6, 7, 0, 9,
        f, 5, 6, 7, 8, 9, 0

En ce moment, ce que j'ai fait est de créer le tableau 7x13x13 et d'insérer les données de sorte que j'ai une ligne et une colonne de zéros, mais je préférerais de loin les chaînes.

Je suppose que je pourrais simplement écrire une macro Excel pour remplacer les zéros par des chaînes. Cependant, le problème est que NumPy ne peut pas convertir string en float, si j'essaye de réaffecter ces zéros comme chaînes que je veux.

23
emmagras

Numpy gérera très bien les tableaux à n dimensions, mais peut-être que les installations sont limitées à des tableaux à 2 dimensions. Je ne sais même pas à quoi vous voulez que le fichier de sortie ressemble.

Beaucoup de gens qui souhaiteraient des colonnes nommées négligent les capacités recarray () de numpy. Bon à savoir mais qui ne "nomme" qu'une dimension.

Pour deux dimensions, Pandas est très cool.

In [275]: DataFrame.from_items([('A', [1, 2, 3]), ('B', [4, 5, 6])],
   .....:                      orient='index', columns=['one', 'two', 'three'])
Out[275]: 
   one  two  three
A    1    2      3
B    4    5      6

Si la sortie est le seul problème que vous essayez de résoudre ici, je m'en tiendrai probablement à quelques lignes de magie codée à la main car cela sera moins lourd que d'installer un autre package pour une fonctionnalité.

13
Phil Cooper

Avec pandas.DataFrame.to_csv vous pouvez écrire les colonnes et l'index dans un fichier:

import numpy as np
import pandas as pd

A = np.random.randint(0, 10, size=36).reshape(6, 6)
names = [_ for _ in 'abcdef']
df = pd.DataFrame(A, index=names, columns=names)
df.to_csv('df.csv', index=True, header=True, sep=' ')

vous donnera les éléments suivants df.csv fichier:

  a b c d e f 
a 1 5 5 0 4 4 
b 2 7 5 4 0 9 
c 6 5 6 9 7 0 
d 4 3 7 9 9 3 
e 8 1 5 1 9 0 
f 2 8 0 0 5 1    
31
bmu

Je pense que cela fait l'affaire de manière générique

Contribution

mats = array([[[0, 1, 2, 3, 4, 5],
    [1, 0, 3, 4, 5, 6],
    [2, 3, 0, 5, 6, 7],
    [3, 4, 5, 0, 7, 8],
    [4, 5, 6, 7, 0, 9],
    [5, 6, 7, 8, 9, 0]],

   [[0, 1, 2, 3, 4, 5],
    [1, 0, 3, 4, 5, 6],
    [2, 3, 0, 5, 6, 7],
    [3, 4, 5, 0, 7, 8],
    [4, 5, 6, 7, 0, 9],
    [5, 6, 7, 8, 9, 0]]])

Code

# Recursively makes pyramiding column and row headers
def make_head(n):
    pre = ''
    if n/26:
        pre = make_head(n/26-1)

    alph = "abcdefghijklmnopqrstuvwxyz"
    pre+= alph[n%26]
    return pre

# Generator object to create header items for n-rows or n-cols
def gen_header(nitems):
    n = -1
    while n<nitems:
        n+=1
        yield make_head(n)

# Convert numpy to list
lmats = mats.tolist()

# Loop through each "matrix"
for mat in lmats:
    # Pre store number of columns as we modify it before working rows
    ncols = len(mat[0])

    # add header value to front of each row from generator object
    for row,hd in Zip(mat,gen_header(len(mat))):
        row.insert(0,hd)

    # Create a "header" line for all the columns
    col_hd = [hd for hd in gen_header(ncols-1)]
    col_hd.insert(0,"A")

    # Insert header line into lead row of matrix
    mat.insert(0,col_hd)

# Convert back to numpy
mats = numpy.array(lmats)

Sortie (valeur stockée dans des tapis):

array([[['A', 'a', 'b', 'c', 'd', 'e', 'f'],
        ['a', '0', '1', '2', '3', '4', '5'],
        ['b', '1', '0', '3', '4', '5', '6'],
        ['c', '2', '3', '0', '5', '6', '7'],
        ['d', '3', '4', '5', '0', '7', '8'],
        ['e', '4', '5', '6', '7', '0', '9'],
        ['f', '5', '6', '7', '8', '9', '0']],

       [['A', 'a', 'b', 'c', 'd', 'e', 'f'],
        ['a', '0', '1', '2', '3', '4', '5'],
        ['b', '1', '0', '3', '4', '5', '6'],
        ['c', '2', '3', '0', '5', '6', '7'],
        ['d', '3', '4', '5', '0', '7', '8'],
        ['e', '4', '5', '6', '7', '0', '9'],
        ['f', '5', '6', '7', '8', '9', '0']]], 
      dtype='|S4')
3
Paul Seeb

Pas vraiment sûr, mais vous pouvez envisager de consulter Pandas .

2
Davide

Je ne connais aucune méthode pour ajouter des en-têtes à la matrice (même si je la trouverais utile). Ce que je ferais, c'est de créer une petite classe qui imprime l'objet pour moi, surchargeant le __str__ une fonction.

Quelque chose comme ça:

class myMat:
    def __init__(self, mat, name):
        self.mat = mat
        self.name = name
        self.head = ['a','b','c','d','e','f']
        self.sep = ','

    def __str__(self):
        s = "%s%s"%(self.name,self.sep)
        for x in self.head:
            s += "%s%s"%(x,self.sep)
        s = s[:-len(self.sep)] + '\n'

        for i in range(len(self.mat)):
            row = self.mat[i]
            s += "%s%s"%(self.head[i],self.sep)
            for x in row:
                s += "%s%s"%(str(x),self.sep)
            s += '\n'
        s = s[:-len(self.sep)-len('\n')]

        return s

Ensuite, vous pouvez facilement les imprimer avec les en-têtes, en utilisant le code suivant:

print myMat(A,'A')
print myMat(B,'B')
1
Oriol Nieto