แผนการกระจายใน Pandas / Pyplot: วิธีการลงจุดตามหมวดหมู่


90

ฉันกำลังพยายามสร้างพล็อตการกระจายอย่างง่ายใน pyplot โดยใช้วัตถุ Pandas DataFrame แต่ต้องการวิธีที่มีประสิทธิภาพในการพล็อตตัวแปรสองตัว แต่มีสัญลักษณ์ที่กำหนดโดยคอลัมน์ที่สาม (คีย์) ฉันได้ลองใช้ df.groupby หลายวิธีแล้ว แต่ไม่สำเร็จ สคริปต์ df ตัวอย่างอยู่ด้านล่าง สีนี้จะแสดงเครื่องหมายตาม "key1" แต่ Id ต้องการดูคำอธิบายแผนภูมิที่มีหมวดหมู่ "key1" ฉันปิด? ขอบคุณ.

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
df = pd.DataFrame(np.random.normal(10,1,30).reshape(10,3), index = pd.date_range('2010-01-01', freq = 'M', periods = 10), columns = ('one', 'two', 'three'))
df['key1'] = (4,4,4,6,6,6,8,8,8,8)
fig1 = plt.figure(1)
ax1 = fig1.add_subplot(111)
ax1.scatter(df['one'], df['two'], marker = 'o', c = df['key1'], alpha = 0.8)
plt.show()

คำตอบ:


120

คุณสามารถใช้scatterสิ่งนี้ได้ แต่ต้องมีค่าตัวเลขสำหรับคุณkey1และคุณจะไม่มีคำอธิบายแผนภูมิอย่างที่คุณสังเกตเห็น

จะดีกว่าที่จะใช้plotสำหรับหมวดหมู่ที่ไม่ต่อเนื่องเช่นนี้ ตัวอย่างเช่น:

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
np.random.seed(1974)

# Generate Data
num = 20
x, y = np.random.random((2, num))
labels = np.random.choice(['a', 'b', 'c'], num)
df = pd.DataFrame(dict(x=x, y=y, label=labels))

groups = df.groupby('label')

# Plot
fig, ax = plt.subplots()
ax.margins(0.05) # Optional, just adds 5% padding to the autoscaling
for name, group in groups:
    ax.plot(group.x, group.y, marker='o', linestyle='', ms=12, label=name)
ax.legend()

plt.show()

ป้อนคำอธิบายภาพที่นี่

หากคุณต้องการให้สิ่งต่างๆดูเหมือนpandasสไตล์เริ่มต้นให้อัปเดตrcParamsด้วยสไตล์ชีทแพนด้าและใช้ตัวสร้างสี (ฉันยังปรับแต่งตำนานเล็กน้อย):

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
np.random.seed(1974)

# Generate Data
num = 20
x, y = np.random.random((2, num))
labels = np.random.choice(['a', 'b', 'c'], num)
df = pd.DataFrame(dict(x=x, y=y, label=labels))

groups = df.groupby('label')

# Plot
plt.rcParams.update(pd.tools.plotting.mpl_stylesheet)
colors = pd.tools.plotting._get_standard_colors(len(groups), color_type='random')

fig, ax = plt.subplots()
ax.set_color_cycle(colors)
ax.margins(0.05)
for name, group in groups:
    ax.plot(group.x, group.y, marker='o', linestyle='', ms=12, label=name)
ax.legend(numpoints=1, loc='upper left')

plt.show()

ป้อนคำอธิบายภาพที่นี่


เหตุใดในตัวอย่าง RGB ด้านบนจึงแสดงสัญลักษณ์สองครั้งในคำอธิบายแผนภูมิ จะแสดงเพียงครั้งเดียวได้อย่างไร?
Steve Schulist

1
@SteveSchulist - ใช้ax.legend(numpoints=1)เพื่อแสดงเครื่องหมายเพียงตัวเดียว มีสองเส้นเช่นเดียวกับ a Line2Dมักจะมีเส้นเชื่อมระหว่างเครื่องหมายทั้งสอง
Joe Kington

รหัสนี้ใช้ได้กับฉันเท่านั้นหลังจากเพิ่มplt.hold(True)หลังax.plot()คำสั่ง คิดว่าทำไม?
Yuval Atzmon

set_color_cycle() ถูกเลิกใช้งานใน matplotlib 1.5 มี set_prop_cycle()แล้วตอนนี้
เบียร์

52

ง่ายๆแค่ทำSeaborn ( pip install seaborn) เป็น oneliner

sns.scatterplot(x_vars="one", y_vars="two", data=df, hue="key1") :

import seaborn as sns
import pandas as pd
import numpy as np
np.random.seed(1974)

df = pd.DataFrame(
    np.random.normal(10, 1, 30).reshape(10, 3),
    index=pd.date_range('2010-01-01', freq='M', periods=10),
    columns=('one', 'two', 'three'))
df['key1'] = (4, 4, 4, 6, 6, 6, 8, 8, 8, 8)

sns.scatterplot(x="one", y="two", data=df, hue="key1")

ป้อนคำอธิบายภาพที่นี่

นี่คือ dataframe สำหรับการอ้างอิง:

ป้อนคำอธิบายภาพที่นี่

เนื่องจากคุณมีคอลัมน์ตัวแปรสามคอลัมน์ในข้อมูลของคุณคุณอาจต้องการพล็อตมิติข้อมูลแบบคู่ทั้งหมดด้วย:

sns.pairplot(vars=["one","two","three"], data=df, hue="key1")

ป้อนคำอธิบายภาพที่นี่

https://rasbt.github.io/mlxtend/user_guide/plotting/category_scatter/เป็นอีกทางเลือกหนึ่ง


19

ด้วยplt.scatterฉันคิดได้เพียงอย่างเดียวคือการใช้ศิลปินพร็อกซี:

df = pd.DataFrame(np.random.normal(10,1,30).reshape(10,3), index = pd.date_range('2010-01-01', freq = 'M', periods = 10), columns = ('one', 'two', 'three'))
df['key1'] = (4,4,4,6,6,6,8,8,8,8)
fig1 = plt.figure(1)
ax1 = fig1.add_subplot(111)
x=ax1.scatter(df['one'], df['two'], marker = 'o', c = df['key1'], alpha = 0.8)

ccm=x.get_cmap()
circles=[Line2D(range(1), range(1), color='w', marker='o', markersize=10, markerfacecolor=item) for item in ccm((array([4,6,8])-4.0)/4)]
leg = plt.legend(circles, ['4','6','8'], loc = "center left", bbox_to_anchor = (1, 0.5), numpoints = 1)

และผลลัพธ์คือ:

ป้อนคำอธิบายภาพที่นี่


10

คุณสามารถใช้ df.plot.scatter และส่งอาร์เรย์ไปยังอาร์กิวเมนต์ c = ที่กำหนดสีของแต่ละจุด:

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
df = pd.DataFrame(np.random.normal(10,1,30).reshape(10,3), index = pd.date_range('2010-01-01', freq = 'M', periods = 10), columns = ('one', 'two', 'three'))
df['key1'] = (4,4,4,6,6,6,8,8,8,8)
colors = np.where(df["key1"]==4,'r','-')
colors[df["key1"]==6] = 'g'
colors[df["key1"]==8] = 'b'
print(colors)
df.plot.scatter(x="one",y="two",c=colors)
plt.show()

ป้อนคำอธิบายภาพที่นี่


4

คุณยังสามารถลองAltairหรือggpotซึ่งเน้นไปที่การแสดงภาพที่เปิดเผยได้

import numpy as np
import pandas as pd
np.random.seed(1974)

# Generate Data
num = 20
x, y = np.random.random((2, num))
labels = np.random.choice(['a', 'b', 'c'], num)
df = pd.DataFrame(dict(x=x, y=y, label=labels))

รหัส Altair

from altair import Chart
c = Chart(df)
c.mark_circle().encode(x='x', y='y', color='label')

ป้อนคำอธิบายภาพที่นี่

รหัส ggplot

from ggplot import *
ggplot(aes(x='x', y='y', color='label'), data=df) +\
geom_point(size=50) +\
theme_bw()

ป้อนคำอธิบายภาพที่นี่


4

จาก matplotlib 3.1 เป็นต้นไปคุณสามารถใช้.legend_elements(). ตัวอย่างที่แสดงให้เห็นในการสร้างตำนานอัตโนมัติ ข้อดีคือสามารถใช้การเรียกแบบกระจายเดียวได้

ในกรณีนี้:

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

df = pd.DataFrame(np.random.normal(10,1,30).reshape(10,3), 
                  index = pd.date_range('2010-01-01', freq = 'M', periods = 10), 
                  columns = ('one', 'two', 'three'))
df['key1'] = (4,4,4,6,6,6,8,8,8,8)


fig, ax = plt.subplots()
sc = ax.scatter(df['one'], df['two'], marker = 'o', c = df['key1'], alpha = 0.8)
ax.legend(*sc.legend_elements())
plt.show()

ป้อนคำอธิบายภาพที่นี่

ในกรณีที่ไม่ได้กำหนดให้คีย์เป็นตัวเลขโดยตรงจะมีลักษณะเป็น

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

df = pd.DataFrame(np.random.normal(10,1,30).reshape(10,3), 
                  index = pd.date_range('2010-01-01', freq = 'M', periods = 10), 
                  columns = ('one', 'two', 'three'))
df['key1'] = list("AAABBBCCCC")

labels, index = np.unique(df["key1"], return_inverse=True)

fig, ax = plt.subplots()
sc = ax.scatter(df['one'], df['two'], marker = 'o', c = index, alpha = 0.8)
ax.legend(sc.legend_elements()[0], labels)
plt.show()

ป้อนคำอธิบายภาพที่นี่


ฉันได้รับข้อผิดพลาดแจ้งว่าวัตถุ "PathCollection" ไม่มีแอตทริบิวต์ "legends_elements" รหัสของฉันมีดังนี้ fig, ax = plt.subplots(1, 1, figsize = (4,4)) scat = ax.scatter(rand_jitter(important_dataframe["workout_type_int"], jitter = 0.04), important_dataframe["distance"], c = color_list, marker = 'o', alpha = 0.9) print(scat.legends_elements()) #ax.legend(*scat.legend_elements())
Nandish Patel

1
@NandishPatel ตรวจสอบประโยคแรกของคำตอบนี้ ยังให้แน่ใจว่าจะไม่ให้เกิดความสับสนและlegends_elements legend_elements
ImportanceOfBeingErnest

ใช่ขอบคุณ. นั่นเป็นการพิมพ์ผิด (ตำนาน / ตำนาน) ฉันกำลังทำงานบางอย่างตั้งแต่ 6 ชั่วโมงที่แล้วดังนั้นเวอร์ชัน Matplotlib จึงไม่เกิดขึ้นกับฉัน ฉันคิดว่าฉันกำลังใช้อันล่าสุด ฉันสับสนที่เอกสารระบุว่ามีวิธีการดังกล่าว แต่รหัสให้ข้อผิดพลาด ขอขอบคุณอีกครั้ง. ฉันสามารถนอนหลับได้แล้ว
Nandish Patel

2

มันค่อนข้าง hacky แต่คุณสามารถใช้one1เป็นFloat64Indexจะทำทุกอย่างในหนึ่งไป:

df.set_index('one').sort_index().groupby('key1')['two'].plot(style='--o', legend=True)

ป้อนคำอธิบายภาพที่นี่

โปรดทราบว่าเป็นของ 0.20.3, การเรียงลำดับดัชนีเป็นสิ่งที่จำเป็นและตำนานเป็นwonky บิต


1

ซีบอร์นมีฟังก์ชั่นห่อหุ้มที่ทำงานscatterplotได้อย่างมีประสิทธิภาพมากขึ้น

sns.scatterplot(data = df, x = 'one', y = 'two', data =  'key1'])
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.