Поверните Pandas DataFrame строк в гистограмму

Предположим, что у меня есть DataFrame, созданный следующим образом:

import pandas as pd
s1 = pd.Series(['a', 'b', 'a', 'c', 'a', 'b'])
s2 = pd.Series(['a', 'f', 'a', 'd', 'a', 'f', 'f'])
d = pd.DataFrame({'s1': s1, 's2', s2})

В строках реальных данных довольно много разреженности. Я хотел бы создать гистограммы появления строк, которые выглядят как то, что генерируется d.hist() (например, с подзаголовками) для s1 и s2 (по одному на подзаговор).

Просто выполнение d.hist() дает эту ошибку:

/Library/Python/2.7/site-packages/pandas/tools/plotting.pyc in hist_frame(data, column, by, grid, xlabelsize, xrot, ylabelsize, yrot, ax, sharex, sharey, **kwds)
   1725         ax.xaxis.set_visible(True)
   1726         ax.yaxis.set_visible(True)
-> 1727         ax.hist(data[col].dropna().values, **kwds)
   1728         ax.set_title(col)
   1729         ax.grid(grid)

/Library/Python/2.7/site-packages/matplotlib/axes.pyc in hist(self, x, bins, range, normed, weights, cumulative, bottom, histtype, align, orientation, rwidth, log, color, label, stacked, **kwargs)
   8099             # this will automatically overwrite bins,
   8100             # so that each histogram uses the same bins
-> 8101             m, bins = np.histogram(x[i], bins, weights=w[i], **hist_kwargs)
   8102             if mlast is None:
   8103                 mlast = np.zeros(len(bins)-1, m.dtype)

/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/numpy/lib/function_base.pyc in histogram(a, bins, range, normed, weights, density)
    167             else:
    168                 range = (a.min(), a.max())
--> 169         mn, mx = [mi+0.0 for mi in range]
    170         if mn == mx:
    171             mn -= 0.5

TypeError: cannot concatenate 'str' and 'float' objects

Я предполагаю, что могу вручную пройти через каждую серию, сделать value_counts(), затем value_counts() ее как график value_counts() и вручную создать подзаголовки. Я хотел проверить, есть ли более простой способ.

Ответ 1

Воспроизведение данных:

import pandas as pd
s1 = pd.Series(['a', 'b', 'a', 'c', 'a', 'b'])
s2 = pd.Series(['a', 'f', 'a', 'd', 'a', 'f', 'f'])
d = pd.DataFrame({'s1': s1, 's2': s2})

Чтобы получить гистограмму с подзаголовками по желанию:

d.apply(pd.value_counts).plot(kind='bar', subplots=True)

enter image description here

ОП упоминает pd.value_counts в вопросе. Я думаю, что недостающая часть состоит в том, что нет причин "вручную" создавать нужный штрих-график.

Вывод из d.apply(pd.value_counts) является d.apply(pd.value_counts) pandas. Мы можем отображать значения, как и любой другой фрейм, и выбирать опцию subplots=True дает нам то, что мы хотим.

Ответ 2

Вы можете использовать pd.value_counts (value_counts также является методом серии):

In [20]: d.apply(pd.value_counts)
Out[20]: 
   s1  s2
a   3   3
b   2 NaN
c   1 NaN
d NaN   1
f NaN   3

и застроить полученный DataFrame.

Ответ 3

Я бы запустил серию в collections.Counter (документация) (возможно, вам сначала нужно будет преобразовать его в список). Я не эксперт по pandas, но я думаю, что вы должны свернуть объект Counter обратно в Series, индексированную строками, и использовать ее для создания ваших сюжетов.

Это не работает, потому что он (правильно) поднимает ошибки, когда он пытается угадать, где должны быть края бункера, что просто не имеет смысла для строк.