2015-02-09 16 views
15

Ho una lista di stringhe:Come creare un istogramma da un elenco di stringhe in Python?

a = ['a', 'a', 'a', 'a', 'b', 'b', 'c', 'c', 'c', 'd', 'e', 'e', 'e', 'e', 'e'] 

Voglio fare un istogramma per la visualizzazione della distribuzione di frequenza delle lettere. Posso creare un elenco che contenga il conteggio di ciascuna lettera utilizzando i seguenti codici:

from itertools import groupby 
b = [len(list(group)) for key, group in groupby(a)] 

Come si effettua l'istogramma? Potrei avere un milione di tali elementi nell'elenco a.

+6

'da collezioni importare contatore; istogramma = Contatore (testo) ' –

+0

Allora, qual è l'istogramma per te? –

+0

prima di tutto dovresti usare 'Counter' ...groupby ti mancherà per '['a', 'a', 'b', 'b', 'a']' (tra le altre cose) –

risposta

24

Molto facile con Pandas.

import pandas 
from collections import Counter 
a = ['a', 'a', 'a', 'a', 'b', 'b', 'c', 'c', 'c', 'd', 'e', 'e', 'e', 'e', 'e'] 
letter_counts = Counter(a) 
df = pandas.DataFrame.from_dict(letter_counts, orient='index') 
df.plot(kind='bar') 

noti che Counter sta facendo un conteggio di frequenza, quindi il nostro tipo di trama è 'bar' non 'hist'.

histogram of letter counts

+0

Fresco, non confuso! Ma come si costruisce un istogramma continuo? Devo cambiare kind = bar per kind = hist? – Gray

+0

Ho più di 1 milione di elementi nella lista, quindi suppongo che la trama della barra abbia qualche difficoltà a visualizzare le frequenze. – Gray

+0

@Gray, se vuoi appianarlo suggerisco 'kind = 'area'' – notconfusing

1

Check out matplotlib.pyplot.bar. C'è anche numpy.histogram che è più flessibile se si vogliono bidoni più larghi.

5

Piuttosto che utilizzare groupby() (che richiede l'input da ordinare), utilizzare collections.Counter(); questo non ha bisogno di creare elenchi di intermediazione solo per contare ingressi:

from collections import Counter 

counts = Counter(a) 

Non hai davvero specificato ciò che si considera di essere un 'istogramma'. Assumiamo si voleva fare questo sul terminale:

width = 120 # Adjust to desired width 
longest_key = max(len(key) for key in counts) 
graph_width = width - longest_key - 2 
widest = counts.most_common(1)[0][1] 
scale = graph_width/float(widest) 

for key, size in sorted(counts.items()): 
    print('{}: {}'.format(key, int(size * scale) * '*')) 

Demo:

>>> from collections import Counter 
>>> a = ['a', 'a', 'a', 'a', 'b', 'b', 'c', 'c', 'c', 'd', 'e', 'e', 'e', 'e', 'e'] 
>>> counts = Counter(a) 
>>> width = 120 # Adjust to desired width 
>>> longest_key = max(len(key) for key in counts) 
>>> graph_width = width - longest_key - 2 
>>> widest = counts.most_common(1)[0][1] 
>>> scale = graph_width/float(widest) 
>>> for key, size in sorted(counts.items()): 
...  print('{}: {}'.format(key, int(size * scale) * '*')) 
... 
a: ********************************************************************************************* 
b: ********************************************** 
c: ********************************************************************** 
d: *********************** 
e: ********************************************************************************************************************* 

strumenti più sofisticati si trovano nei numpy.histogram() e matplotlib.pyplot.hist() funzioni. Questi fanno il conteggio per voi, con matplotlib.pyplot.hist() anche fornendo output grafico.

+0

Grazie Martijin! Questo è un modo intelligente ma come posso creare grafici stampabili? – Gray

+0

E come usare numpy.histogram() per risolvere questo problema? Scusa, non sono un programmatore. – Gray

+0

@Gray: ad essere onesti, non so né ho il tempo giusto per scoprirlo. Ci sono tutorial per le biblioteche, ti suggerisco di seguirli! :-) –

7

Come @notconfusing indicate sopra può essere risolto con Panda e contatore. Se per qualsiasi motivo è necessario non utilizzare Pandas si può ottenere solo con matplotlib utilizzando la funzione nel seguente codice:

from collections import Counter 
import numpy as np 
import matplotlib.pyplot as plt 

a = ['a', 'a', 'a', 'a', 'b', 'b', 'c', 'c', 'c', 'd', 'e', 'e', 'e', 'e', 'e'] 
letter_counts = Counter(a) 

def plot_bar_from_counter(counter, ax=None): 
    """" 
    This function creates a bar plot from a counter. 

    :param counter: This is a counter object, a dictionary with the item as the key 
    and the frequency as the value 
    :param ax: an axis of matplotlib 
    :return: the axis wit the object in it 
    """ 

    if ax is None: 
     fig = plt.figure() 
     ax = fig.add_subplot(111) 

    frequencies = counter.values() 
    names = counter.keys() 

    x_coordinates = np.arange(len(counter)) 
    ax.bar(x_coordinates, frequencies, align='center') 

    ax.xaxis.set_major_locator(plt.FixedLocator(x_coordinates)) 
    ax.xaxis.set_major_formatter(plt.FixedFormatter(names)) 

    return ax 

plot_bar_from_counter(letter_counts) 
plt.show() 

che produrrà enter image description here

0

modo semplice ed efficace per rendere il carattere Istogramma in pitone

import numpy as np 
 

 
import matplotlib.pyplot as plt 
 

 
from collections import Counter 
 

 

 

 
a = [] 
 
count =0 
 
d = dict() 
 
filename = raw_input("Enter file name: ") 
 
with open(filename,'r') as f: 
 
    for word in f: 
 
     for letter in word: 
 
      if letter not in d: 
 
       d[letter] = 1 
 
      else: 
 
       d[letter] +=1 
 
num = Counter(d) 
 
x = list(num.values()) 
 
y = list(num.keys()) 
 

 
x_coordinates = np.arange(len(num.keys())) 
 
plt.bar(x_coordinates,x) 
 
plt.xticks(x_coordinates,y) 
 
plt.show() 
 
print x,y

1

ecco una sintetica approccio all-panda:

a = ['a', 'a', 'a', 'a', 'b', 'b', 'c', 'c', 'c', 'd', 'e', 'e', 'e', 'e', 'e'] 
pd.Series(a).value_counts().plot('bar') 

barplot of counts

Problemi correlati