Подтвердить что ты не робот

Создание графиков разметки matplotlib из dataframes в Python pandas

Каков наилучший способ сделать серию диаграмм рассеяния, используя matplotlib из pandas dataframe в Python?

Например, если у меня есть dataframe df, который имеет некоторые столбцы, представляющие интерес, я, как правило, преобразовываю все в массивы:

import matplotlib.pylab as plt
# df is a DataFrame: fetch col1 and col2 
# and drop na rows if any of the columns are NA
mydata = df[["col1", "col2"]].dropna(how="any")
# Now plot with matplotlib
vals = mydata.values
plt.scatter(vals[:, 0], vals[:, 1])

Проблема с преобразованием всего массива перед построением заключается в том, что он заставляет вас вырваться из фреймов данных.

Рассмотрим эти два случая использования, когда полный график данных необходим для построения:

  • Например, если вы хотите теперь просмотреть все значения col3 для соответствующих значений, которые вы построили при вызове scatter, и покрасить каждую точку (или размер) ее стоимость? Вам нужно будет вернуться назад, вытащить значения не-na col1,col2 и проверить, что их соответствующие значения.

    Есть ли способ построения, сохраняя данные? Например:

    mydata = df.dropna(how="any", subset=["col1", "col2"])
    # plot a scatter of col1 by col2, with sizes according to col3
    scatter(mydata(["col1", "col2"]), s=mydata["col3"])
    
  • Аналогично, представьте, что вы хотите фильтровать или окрашивать каждую точку по-разному в зависимости от значений некоторых ее столбцов. Например. что, если вы хотите автоматически строить метки точек, которые встречаются с определенным обрезанием на col1, col2 вместе с ними (где метки хранятся в другом столбце df), или покрасить эти точки по-разному, как люди делают с кадрами данных в R Например:

    mydata = df.dropna(how="any", subset=["col1", "col2"]) 
    myscatter = scatter(mydata[["col1", "col2"]], s=1)
    # Plot in red, with smaller size, all the points that 
    # have a col2 value greater than 0.5
    myscatter.replot(mydata["col2"] > 0.5, color="red", s=0.5)
    

Как это можно сделать?

РЕДАКТИРОВАТЬ Ответ экипажу:

Вы говорите, что наилучшим способом является построение каждого условия (например, subset_a, subset_b) отдельно. Что делать, если у вас много условий, например. вы хотите разбить рассеиватели на 4 типа точек или даже больше, построив каждый в другой форме/цвете. Как вы можете элегантно применять условия a, b, c и т.д. И убедиться, что вы затем задумали "остальное" (вещи не в любом из этих условий) в качестве последнего шага?

Аналогично, в вашем примере, где вы рисуете col1,col2 по-разному на основе col3, что, если есть значения NA, которые нарушают связь между col1,col2,col3? Например, если вы хотите построить все значения col2 на основе их значений col3, но некоторые строки имеют значение NA в col1 или col3, заставляя вас сначала использовать dropna. Итак, вы бы сделали:

mydata = df.dropna(how="any", subset=["col1", "col2", "col3")

тогда вы можете построить с помощью mydata, как вы показываете, - разметку разброса между col1,col2 с использованием значений col3. Но mydata будет отсутствовать некоторые точки, которые имеют значения для col1,col2, но являются NA для col3, и они все еще должны быть построены... так как бы вы в основном заложили "остальную" информацию, т.е. точки, которые не находятся в отфильтрованном наборе mydata?

4b9b3361

Ответ 1

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

df = pd.DataFrame(np.random.randn(10,2), columns=['col1','col2'])
df['col3'] = np.arange(len(df))**2 * 100 + 100

In [5]: df
Out[5]: 
       col1      col2  col3
0 -1.000075 -0.759910   100
1  0.510382  0.972615   200
2  1.872067 -0.731010   500
3  0.131612  1.075142  1000
4  1.497820  0.237024  1700

Изменение размера точки разброса на основе другого столбца

plt.scatter(df.col1, df.col2, s=df.col3)
# OR (with pandas 0.13 and up)
df.plot(kind='scatter', x='col1', y='col2', s=df.col3)

enter image description here

Изменение цвета точки разброса на основе другого столбца

colors = np.where(df.col3 > 300, 'r', 'k')
plt.scatter(df.col1, df.col2, s=120, c=colors)
# OR (with pandas 0.13 and up)
df.plot(kind='scatter', x='col1', y='col2', s=120, c=colors)

enter image description here

График рассеяния с легендой

Однако самый простой способ создать график рассеяния с легендой - вызвать plt.scatter один раз для каждого типа точки.

cond = df.col3 > 300
subset_a = df[cond].dropna()
subset_b = df[~cond].dropna()
plt.scatter(subset_a.col1, subset_a.col2, s=120, c='b', label='col3 > 300')
plt.scatter(subset_b.col1, subset_b.col2, s=60, c='r', label='col3 <= 300') 
plt.legend()

enter image description here

Update

Из того, что я могу сказать, matplotlib просто пропускает точки с координатами NA x/y или настройками стиля NA (например, цвет/размер). Чтобы найти точки, пропущенные из-за NA, попробуйте метод isnull: df[df.col3.isnull()]

Чтобы разбить список точек на многие типы, посмотрите numpy select, который является векторизованным if-then-else реализации и принимает необязательное значение по умолчанию. Например:

df['subset'] = np.select([df.col3 < 150, df.col3 < 400, df.col3 < 600],
                         [0, 1, 2], -1)
for color, label in zip('bgrm', [0, 1, 2, -1]):
    subset = df[df.subset == label]
    plt.scatter(subset.col1, subset.col2, s=120, c=color, label=str(label))
plt.legend()

enter image description here

Ответ 2

В Garrett мало что можно добавить, но pandas также имеет метод scatter. Используя это, это так же просто, как

df = pd.DataFrame(np.random.randn(10,2), columns=['col1','col2'])
df['col3'] = np.arange(len(df))**2 * 100 + 100
df.plot.scatter('col1', 'col2', df['col3'])

размер графика в col3 до col1-col2

Ответ 3

Я рекомендую использовать альтернативный метод с использованием seaborn который является более мощным инструментом для построения данных. Вы можете использовать seaborn scatterplot и определить столб 3 как hue и size.

Рабочий код:

import pandas as pd
import seaborn as sns
import numpy as np

#creating sample data 
sample_data={'col_name_1':np.random.rand(20),
      'col_name_2': np.random.rand(20),'col_name_3': np.arange(20)*100}
df= pd.DataFrame(sample_data)
sns.scatterplot(x="col_name_1", y="col_name_2", data=df, hue="col_name_3",size="col_name_3")

enter image description here