Как построить параллельные координаты на pandas DataFrame с некоторыми столбцами, содержащими строки?

Я хотел бы построить параллельные координаты для pandas DataFrame, содержащего столбцы с числами и другие столбцы, содержащие строки в качестве значений.

Описание проблемы

У меня есть следующий тестовый код, который работает для построения параллельных координат с числами:

import pandas as pd
import matplotlib.pyplot as plt
from pandas.tools.plotting import parallel_coordinates

df = pd.DataFrame([["line 1",20,30,100],\
    ["line 2",10,40,90],["line 3",10,35,120]],\
    columns=["element","var 1","var 2","var 3"])
parallel_coordinates(df,"element")
plt.show()

В итоге отображается следующий рисунок: введите здесь описание изображения

Однако я хотел бы попытаться добавить к моему графику некоторые переменные со строками. Но когда я запускаю следующий код:

df2 = pd.DataFrame([["line 1",20,30,100,"N"],\
    ["line 2",10,40,90,"N"],["line 3",10,35,120,"N-1"]],\
    columns=["element","var 1","var 2","var 3","regime"])
parallel_coordinates(df2,"element")
plt.show()

Я получаю эту ошибку:

ValueError: неверный литерал для float(): N

Что, я полагаю, означает, что функция parallel_coordinates не принимает строки.

Пример того, что я пытаюсь сделать

Я пытаюсь сделать что-то вроде этого примера, где раса и пол являются строками, а не числами:

График параллельных координат с включенными строковыми значениями

Вопрос

Есть ли способ выполнить такую ​​графику, используя pandas parallel_coordinates? Если нет, то как я мог попытаться сделать такую ​​графику? Может с matplotlib?

Я должен упомянуть, что я особенно ищу решение для Python 2.5 с версией pandas 0.9.0.


person Cedric Zoppolo    schedule 22.06.2017    source источник
comment
Я нашел вопрос о построении параллельных координат с помощью matplotlib в разделе stackoverflow. com/questions/8230638/, но не решает то, что я ищу...   -  person Cedric Zoppolo    schedule 30.06.2017


Ответы (2)


Мне было не совсем понятно, что вы хотели сделать со столбцом regime.

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

parallel_coordinates(df2, class_column='element', cols=['var 1', 'var 2', 'var 3'])

введите описание изображения здесь

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

Если да, то вам нужно преобразовать ваши категориальные переменные (здесь regime) в числовое значение. Для этого я воспользовался советом, который нашел на этом сайте.

df2.regime = df2.regime.astype('category')
df2['regime_encoded'] = df2.regime.cat.codes


print(df2)
    element var 1   var 2   var 3   regime  regime_encoded
0   line 1  20      30      100     N       0
1   line 2  10      40      90      N       0
2   line 3  10      35      120     N-1     1

этот код создает новый столбец (regime_encoded), где каждое значение режима категории кодируется целым числом. Затем вы можете построить свой новый фрейм данных, включая вновь созданный столбец:

parallel_coordinates(df2[['element', 'var 1', 'var 2', 'var 3', 'regime_encoded']],"element")

введите описание изображения здесь

Проблема в том, что значения кодирования для категориальной переменной (0, 1) не имеют ничего общего с диапазоном других ваших переменных, поэтому кажется, что все линии стремятся к одной и той же точке. Ответ заключается в том, чтобы масштабировать кодировку по сравнению с диапазоном ваших данных (здесь я сделал это очень просто, потому что ваши данные были ограничены от 0 до 120, вам, вероятно, нужно масштабировать от минимального значения, если это не так в вашем реальном фрейме данных ).

df2['regime_encoded'] = df2.regime.cat.codes * max(df2.max(axis=1, numeric_only=True))
parallel_coordinates(df2[['element', 'var 1', 'var 2', 'var 3', 'regime_encoded']],"element")

введите описание изображения здесь

Чтобы лучше соответствовать вашему примеру, вы можете добавить аннотации:

df2['regime_encoded'] = df2.regime.cat.codes * max(df2.max(axis=1, numeric_only=True)
parallel_coordinates(df2[['element', 'var 1', 'var 2', 'var 3', 'regime_encoded']],"element")
ax = plt.gca()
for i,(label,val) in df2.loc[:,['regime','regime_encoded']].drop_duplicates().iterrows():
    ax.annotate(label, xy=(3,val), ha='left', va='center')

введите описание изображения здесь

person Diziet Asahi    schedule 13.07.2017
comment
Какую версию питона вы используете? Я предполагаю, что Python 3.5, так как я мог бы воспроизвести ваше решение под python в любом месте с помощью IPython 3.5. Однако я получаю TypeError: data type "category" not understood под Python 2.5 и 2.7. В частности, я ищу решение для Python 2.5. Я знаю, что это может быть сложно, но бывает, что я застрял с этой версией из-за того, что другое программное обеспечение использует такую ​​версию Python. Также версия панд будет 0.9.0. - person Cedric Zoppolo; 13.07.2017
comment
P.S.: Я обнаружил, что в конце первой строки в вашем последнем опубликованном коде отсутствует скобка. - person Cedric Zoppolo; 13.07.2017
comment
P.S.2: Результат, который вы получите с помощью своего решения, — это именно то, что я искал. Но мне нужно, чтобы он работал под Python 2.5. - person Cedric Zoppolo; 13.07.2017
comment
Хотя я не могу использовать ваш код, он заслуживает того, чтобы быть выбранным ответом, поскольку в нем есть все, что ему нужно. Однако я опубликую свой собственный, поскольку я мог понять, как решить эту проблему, используя ваш собственный ответ;) - person Cedric Zoppolo; 13.07.2017

Основываясь на ответе @Diziet, чтобы получить желаемый график в Python 2.5, мы можем использовать следующий код:

import pandas as pd
import matplotlib.pyplot as plt
from pandas.tools.plotting import parallel_coordinates

def format(input):
    if input == "N":
        output = 0
    elif input == "N-1":
        output = 1
    else:
        output = None
    return output

df2 = pd.DataFrame([["line 1",20,30,100,"N"],\
    ["line 2",10,40,90,"N"],["line 3",10,35,120,"N-1"]],\
    columns=["element","var 1","var 2","var 3","regime"])
df2["regime_encoded"] = df2["regime"].apply(format) * max(df2[["var 1","var 2","var 3"]].max(axis=1))

parallel_coordinates(df2[['element', 'var 1', 'var 2', 'var 3', 'regime_encoded']],"element")
ax = plt.gca()
for i,(label,val) in df2.ix[:,['regime','regime_encoded']].drop_duplicates().iterrows():
    ax.annotate(label, xy=(3,val), ha='left', va='center')

plt.show()

Это приведет к отображению следующего графика:

Результат графика параллельных координат

person Cedric Zoppolo    schedule 13.07.2017