ชนิดข้อมูลแบบหมวดหมู่
แปลงคอลัมน์สตริงที่มีจำนวนค่าที่แตกต่างกันน้อยเป็น pandas Categorical เพื่อลดการใช้หน่วยความจำและเร่งการดำเนินการแบบ groupby
ชนิดข้อมูลแบบหมวดหมู่ เป็นบทเรียน Pandas & NumPy Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Pandas & NumPy Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Pandas & NumPy Academy มีบทเรียนทั้งหมด 4 บทเรียน
ชนิดข้อมูล Categorical คืออะไร
ชนิดข้อมูล Categorical ใน Pandas ออกแบบมาสำหรับคอลัมน์ที่มีค่าจำกัดและเป็นค่าที่แยกจากกันได้ (มีจำนวนค่าที่ไม่ซ้ำกันน้อย) เช่น เพศ สถานะ ภูมิภาค หรือหมวดหมู่สินค้า แทนที่จะจัดเก็บสตริงทั้งหมดซ้ำในทุกแถว Pandas จะจัดเก็บค่าที่ไม่ซ้ำกัน (เรียกว่า หมวดหมู่) เพียงครั้งเดียว และใช้รหัสจำนวนเต็มต่อแถวเพื่ออ้างอิงค่าเหล่านั้น แนวคิดนี้คล้ายกับการใช้ตารางค้นหาหรือชนิด enum ในฐานข้อมูล
import pandas as pd
df = pd.DataFrame({
'region': ['North', 'South', 'East', 'North', 'East', 'South'] * 1000
})
# Without Categorical: object dtype stores every string
print('object dtype memory:', df['region'].memory_usage(deep=True))
# With Categorical: only stores 3 unique values + integer codes
df['region_cat'] = df['region'].astype('category')
print('category dtype memory:', df['region_cat'].memory_usage(deep=True))การสร้าง Categorical Series
แปลงคอลัมน์เป็น Categorical โดยเรียกใช้ .astype('category') กับ Series ใดก็ได้ Categorical Series ที่ได้จะจัดเก็บค่าที่ไม่ซ้ำกันไว้ใน .cat.categories และจัดเก็บรหัสตำแหน่งจำนวนเต็มไว้ใน .cat.codes นอกจากนี้ คุณยังสร้าง Categorical ได้โดยตรงด้วย pd.Categorical() เพื่อระบุหมวดหมู่และลำดับของหมวดหมู่ไว้ล่วงหน้า
import pandas as pd
s = pd.Series(['low', 'high', 'med', 'high', 'low'])
s_cat = s.astype('category')
print(s_cat.cat.categories) # Index(['high', 'low', 'med'], dtype='object')
print(s_cat.cat.codes) # integer codes per row
# 0 1
# 1 0
# 2 2
# 3 0
# 4 1การประหยัดหน่วยความจำด้วย Categorical
ปริมาณหน่วยความจำที่ประหยัดได้จากชนิดข้อมูล Categorical ขึ้นอยู่กับอัตราส่วนความหลากหลาย (จำนวนค่าที่ไม่ซ้ำกัน ÷ จำนวนแถวทั้งหมด) หากคอลัมน์มีสตริงที่ไม่ซ้ำกัน 5 ค่าและมี 1,000,000 แถว ชนิดข้อมูล object จะจัดเก็บตัวชี้ไปยังสตริง 1 ล้านรายการ (ประมาณ 50+ ไบต์ต่อรายการ) ขณะที่ Categorical จัดเก็บสตริงเพียง 5 ค่าและจำนวนเต็มขนาด 8 บิตอีก 1 ล้านค่า การประหยัดอาจอยู่ที่ 5–20 เท่า ทำให้คอลัมน์ขนาด 50 MB เหลือเพียง 2–5 MB
import pandas as pd
import numpy as np
n = 1_000_000
statuses = np.random.choice(['active', 'inactive', 'pending'], size=n)
df = pd.DataFrame({'status': statuses})
object_mem = df['status'].memory_usage(deep=True) / 1e6
df['status'] = df['status'].astype('category')
cat_mem = df['status'].memory_usage(deep=True) / 1e6
print(f'Object dtype: {object_mem:.1f} MB')
print(f'Category dtype: {cat_mem:.1f} MB')
print(f'Reduction: {object_mem/cat_mem:.1f}x')Categorical แบบมีลำดับสำหรับการจัดอันดับ
บางครั้งหมวดหมู่มีลำดับตามธรรมชาติ เช่น 'low' < 'medium' < 'high' หรือขนาดเสื้อยืด XS < S < M < L < XL Categorical แบบมีลำดับจะเก็บลำดับนี้ไว้ ทำให้ใช้ตัวดำเนินการเปรียบเทียบที่มีความหมาย (<, >= และอื่น ๆ) ได้ และทำให้ผลลัพธ์ของ groupby เรียงตามลำดับเชิงความหมายที่ถูกต้องแทนการเรียงตามตัวอักษร
import pandas as pd
df = pd.DataFrame({
'priority': ['high', 'low', 'medium', 'high', 'low']
})
priority_type = pd.CategoricalDtype(
categories=['low', 'medium', 'high'],
ordered=True
)
df['priority'] = df['priority'].astype(priority_type)
# Comparison now works correctly
print(df['priority'] >= 'medium')
# 0 True
# 1 False
# 2 True
# 3 True
# 4 Falseการเรียงลำดับ Categorical แบบมีลำดับ
เมื่อคุณเรียงลำดับคอลัมน์ Categorical ที่มีการกำหนดลำดับไว้ Pandas จะใช้ลำดับหมวดหมู่ที่กำหนด แทนการเรียงตามตัวอักษร ซึ่งหมายความว่า 'low' จะอยู่ก่อน 'medium' และ 'medium' จะอยู่ก่อน 'high' ไม่ว่าค่าเหล่านี้จะถูกเรียงในฐานะสตริงอย่างไรก็ตาม เรื่องนี้สำคัญอย่างยิ่งต่อการสร้างตารางสรุปและแผนภูมิที่เรียงลำดับได้ถูกต้อง
import pandas as pd
df = pd.DataFrame({
'severity': pd.Categorical(
['high', 'low', 'medium', 'low', 'high'],
categories=['low', 'medium', 'high'],
ordered=True
),
'count': [5, 20, 8, 15, 3]
})
# sort_values respects the categorical order
print(df.sort_values('severity')[['severity', 'count']])
# severity count
# 1 low 20
# 3 low 15
# 2 medium 8
# 0 high 5
# 4 high 3ความเร็วของ GroupBy ด้วย Categorical
Pandas สามารถเพิ่มประสิทธิภาพการทำงานของ groupby() กับคอลัมน์ Categorical ได้ เนื่องจากทราบกลุ่มที่เป็นไปได้ทั้งหมดล่วงหน้า ซึ่งอาจทำให้ groupby ทำงานเร็วขึ้น 2–5 เท่ากับ DataFrames ขนาดใหญ่ นอกจากนี้ groupby ที่ใช้ Categorical ยังส่งคืนทุกหมวดหมู่ รวมถึงหมวดหมู่ที่ไม่มีข้อมูลด้วย จึงช่วยให้ตารางสรุปมีแถวสำหรับทุกกลุ่มที่คาดไว้เสมอ แม้บางกลุ่มจะมีข้อมูลเป็นศูนย์ก็ตาม
import pandas as pd
import numpy as np
np.random.seed(0)
df = pd.DataFrame({
'region': pd.Categorical(
np.random.choice(['North', 'South', 'East', 'West'], 10),
categories=['North', 'South', 'East', 'West']
),
'sales': np.random.randint(100, 1000, 10)
})
# observed=False shows ALL categories even empty ones
print(df.groupby('region', observed=False)['sales'].sum())การเพิ่มและลบหมวดหมู่
ใช้ตัวเข้าถึง .cat เพื่อจัดการรายการหมวดหมู่ โดย .cat.add_categories() จะเพิ่มค่าที่อนุญาตใหม่ ซึ่งมีประโยชน์ก่อนแทรกข้อมูลใหม่ และ .cat.remove_unused_categories() จะลบป้ายกำกับหมวดหมู่ที่ไม่มีแถวสอดคล้องกัน เหมาะสำหรับใช้หลังการกรองข้อมูล คุณไม่สามารถกำหนดค่าที่ไม่มีอยู่ในหมวดหมู่ได้จนกว่าจะเพิ่มค่านั้นก่อน
import pandas as pd
s = pd.Categorical(['a', 'b', 'a'], categories=['a', 'b', 'c'])
s = pd.Series(s)
print(s.cat.categories) # Index(['a', 'b', 'c'], dtype='object')
print(s.value_counts()) # a:2, b:1, c:0
# Remove unused category 'c'
s = s.cat.remove_unused_categories()
print(s.cat.categories) # Index(['a', 'b'], dtype='object')การเปลี่ยนชื่อป้ายกำกับหมวดหมู่
.cat.rename_categories() ช่วยให้คุณเปลี่ยนป้ายกำกับหมวดหมู่ได้โดยไม่เปลี่ยนรหัสพื้นฐาน เหมาะเมื่อคุณต้องการแสดงชื่อที่เข้าใจง่ายขึ้น เช่น 'M' → 'Male' หรือแก้ไขการใช้ตัวพิมพ์ใหญ่เล็กของป้ายกำกับที่ไม่สอดคล้องกัน โดยไม่ต้องแปลงกลับเป็น object และทำการจับคู่ใหม่ เมธอดนี้รับรายการ (ตามตำแหน่ง) หรือพจนานุกรม (ระบุรายการเป้าหมาย) ได้
import pandas as pd
s = pd.Series(pd.Categorical(['M', 'F', 'M', 'F'], categories=['M', 'F']))
# Rename using a dict
s = s.cat.rename_categories({'M': 'Male', 'F': 'Female'})
print(s)
# 0 Male
# 1 Female
# 2 Male
# 3 Female
print(s.cat.categories) # Index(['Male', 'Female'], dtype='object')กรณีที่ไม่ควรใช้ Categorical
dtype แบบ Categorical ไม่เหมาะเมื่อมีจำนวนค่าที่แตกต่างกันสูง กล่าวคือ หากเกือบทุกแถวมีค่าไม่ซ้ำกัน เช่น รหัสผู้ใช้ ความคิดเห็นแบบข้อความอิสระ หรือ UUID ดัชนีหมวดหมู่จะมีขนาดเกือบเท่ากับข้อมูลเดิม จึงไม่ช่วยประหยัดหน่วยความจำ หลักง่าย ๆ คือ ให้ใช้ Categorical เมื่อจำนวนค่าที่ไม่ซ้ำกันน้อยกว่าประมาณ 50% ของจำนวนแถวทั้งหมด และเหมาะเป็นพิเศษเมื่อมีค่าที่ไม่ซ้ำกันอยู่ในระดับหลักสิบหรือหลักร้อย
import pandas as pd
import numpy as np
df = pd.DataFrame({'user_id': range(1_000_000)})
# High-cardinality: every value is unique — don't use Categorical
object_mem = df['user_id'].astype(str).memory_usage(deep=True) / 1e6
cat_mem = df['user_id'].astype(str).astype('category').memory_usage(deep=True) / 1e6
print(f'String: {object_mem:.1f} MB')
print(f'Category: {cat_mem:.1f} MB')
# Category is WORSE for high-cardinality data!Categorical ในตาราง Pivot และ Groupby
การใช้ Categorical ช่วยให้ รูปแบบผลลัพธ์สม่ำเสมอ ในผลลัพธ์จาก groupby และตาราง Pivot หากไม่ใช้ Categorical กลุ่มที่บังเอิญไม่มีข้อมูลจะถูกละเว้นจากผลลัพธ์โดยไม่มีการแจ้งให้ทราบ ซึ่งอาจทำให้ผลลัพธ์ไม่สอดคล้องกันเมื่อเปรียบเทียบส่วนย่อยของข้อมูลต่าง ๆ เมื่อใช้ Categorical ร่วมกับ observed=False ทุกกลุ่มจะแสดงอยู่ในผลลัพธ์เสมอ
import pandas as pd
df = pd.DataFrame({
'quarter': pd.Categorical(
['Q1', 'Q1', 'Q3'],
categories=['Q1', 'Q2', 'Q3', 'Q4']
),
'revenue': [100, 200, 300]
})
# observed=False includes Q2 and Q4 even though they have no rows
result = df.groupby('quarter', observed=False)['revenue'].sum()
print(result)
# quarter
# Q1 300
# Q2 0
# Q3 300
# Q4 0Categorical และการเรียนรู้ของเครื่อง
ตัวประมาณค่าจำนวนมากของ scikit-learn ต้องการข้อมูลนำเข้าเป็นตัวเลข หากต้องการแปลงคอลัมน์ Categorical เป็นตัวเลขสำหรับโมเดล ให้ใช้ .cat.codes (การเข้ารหัสป้ายกำกับ) หรือ pd.get_dummies() (การเข้ารหัสแบบ one-hot) การเข้ารหัสแบบ one-hot จะหลีกเลี่ยงการสื่อเป็นนัยว่าหมวดหมู่มีความสัมพันธ์ตามลำดับ สำหรับ Categorical ที่มีลำดับ เช่น ระดับความสำคัญ การเข้ารหัสป้ายกำกับ (ใช้รหัสโดยตรง) เป็นวิธีที่เหมาะสมและเก็บข้อมูลลำดับไว้
import pandas as pd
df = pd.DataFrame({
'colour': pd.Categorical(['red', 'blue', 'green', 'red'])
})
# One-hot encode for unordered categories
one_hot = pd.get_dummies(df['colour'], prefix='colour')
print(one_hot)
# colour_blue colour_green colour_red
# 0 0 0 1
# 1 1 0 0
# 2 0 1 0
# 3 0 0 1ตรวจสอบความเข้าใจ
ทดสอบความเข้าใจของคุณเกี่ยวกับ dtype แบบ Categorical
สรุปบทเรียน
ในบทเรียนนี้ คุณได้เรียนรู้ว่า dtype แบบ Categorical จัดเก็บค่าที่ไม่ซ้ำกันเพียงครั้งเดียวและใช้รหัสจำนวนเต็มในแต่ละแถว จึงช่วยประหยัดหน่วยความจำได้มากสำหรับคอลัมน์ที่มีค่าหลากหลายน้อย, ordered Categorical รองรับการเปรียบเทียบที่มีความหมายและการเรียงลำดับที่ถูกต้อง และ groupby with observed=False จะรวมทุกหมวดหมู่ แม้แต่หมวดหมู่ที่ไม่มีข้อมูล ควรหลีกเลี่ยงการใช้ Categorical กับคอลัมน์ที่มีค่าหลากหลายมาก บทถัดไป เราจะเรียนรู้การแยกวิเคราะห์สตริงวันที่อย่างถูกต้องด้วย pd.to_datetime()
คำถามที่พบบ่อย
บทเรียน “ชนิดข้อมูลแบบหมวดหมู่” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “ชนิดข้อมูลแบบหมวดหมู่” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Pandas & NumPy Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Pandas & NumPy Academy มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “ชนิดข้อมูลแบบหมวดหมู่”
แปลงคอลัมน์สตริงที่มีจำนวนค่าที่แตกต่างกันน้อยเป็น pandas Categorical เพื่อลดการใช้หน่วยความจำและเร่งการดำเนินการแบบ groupby คุณปฏิบัติ Pandas & NumPy Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Pandas & NumPy Academy หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน Pandas & NumPy Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน
บทเรียน “ชนิดข้อมูลแบบหมวดหมู่” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน Pandas & NumPy Academy นี้ได้ไหม
ได้ บทเรียน Pandas & NumPy Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- การตรวจสอบชนิดข้อมูลของคอลัมน์
- การแปลงชนิดด้วย astype()
- ชนิดข้อมูลแบบหมวดหมู่
- การแยกวิเคราะห์วันที่อย่างถูกต้อง