สตริงใน DataFrame แต่ dtype เป็นวัตถุ


101

เหตุใดนุ่นจึงบอกฉันว่าฉันมีวัตถุแม้ว่าทุกรายการในคอลัมน์ที่เลือกจะเป็นสตริง - แม้ว่าจะมีการแปลงอย่างชัดเจนก็ตาม

นี่คือ DataFrame ของฉัน:

<class 'pandas.core.frame.DataFrame'>
Int64Index: 56992 entries, 0 to 56991
Data columns (total 7 columns):
id            56992  non-null values
attr1         56992  non-null values
attr2         56992  non-null values
attr3         56992  non-null values
attr4         56992  non-null values
attr5         56992  non-null values
attr6         56992  non-null values
dtypes: int64(2), object(5)

dtype objectห้าของพวกเขา ฉันแปลงวัตถุเหล่านั้นเป็นสตริงอย่างชัดเจน:

for c in df.columns:
    if df[c].dtype == object:
        print "convert ", df[c].name, " to string"
        df[c] = df[c].astype(str)

จากนั้นdf["attr2"]ยังคงมีdtype objectแม้ว่าจะtype(df["attr2"].ix[0]เปิดเผยstrซึ่งถูกต้อง

ความแตกต่างระหว่างนุ่นint64และและfloat64 objectอะไรคือตรรกะเบื้องหลังเมื่อไม่มีdtype str? เหตุใดจึงstrครอบคลุมโดยobject?


มาที่นี่เพราะการรวมล้มเหลวเนื่องจาก 'ประเภทวัตถุ' แม้ว่าทุกสตริงจะ "เป็น" ก็ตาม
Monica Heddneck

คำตอบ:


150

วัตถุ dtype มาจาก NumPy ซึ่งอธิบายประเภทขององค์ประกอบใน ndarray ทุกองค์ประกอบใน ndarray ต้องมีขนาดไบต์เท่ากัน สำหรับ int64 และ float64 จะมีขนาด 8 ไบต์ แต่สำหรับสตริงความยาวของสตริงจะไม่คงที่ ดังนั้นแทนที่จะบันทึกไบต์ของสตริงใน ndarray โดยตรง Pandas ใช้ object ndarray ซึ่งบันทึกพอยน์เตอร์ไปยังอ็อบเจ็กต์เนื่องจาก dtype ของ ndarray ชนิดนี้จึงเป็น object

นี่คือตัวอย่าง:

  • อาร์เรย์ int64 มีค่า int64 4 ค่า
  • อาร์เรย์อ็อบเจ็กต์มี 4 พอยน์เตอร์ถึง 3 อ็อบเจกต์สตริง

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


4
อย่างไรก็ตามการมีคอลัมน์ประเภท 'วัตถุ' มีผลกระทบอย่างมากต่อประสิทธิภาพของการดำเนินการอ่าน / เขียน
DataFrame

ฉันจะส่งคืนประเภทข้อมูลเป็นสตริงได้ไหม ฉันรู้ว่าฉันสามารถใช้ type ได้ตลอดเวลา (df ["column"]. iloc [0]) แต่มันอาจจะเป็น nan ก็ได้
user1953366

10

คำตอบของ @ HYRY ดีมาก ฉันแค่ต้องการให้บริบทเพิ่มเติมเล็กน้อย ..

อาร์เรย์จัดเก็บข้อมูลที่ต่อเนื่องกัน , ขนาดคงที่บล็อกหน่วยความจำ การรวมคุณสมบัติเหล่านี้เข้าด้วยกันเป็นสิ่งที่ทำให้อาร์เรย์รวดเร็วในการเข้าถึงข้อมูล ตัวอย่างเช่นพิจารณาว่าคอมพิวเตอร์ของคุณสามารถจัดเก็บอาร์เรย์ของจำนวนเต็ม 32 บิต[3,0,1]ได้อย่างไร

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

หากคุณขอให้คอมพิวเตอร์ดึงองค์ประกอบที่ 3 ในอาร์เรย์มันจะเริ่มต้นที่จุดเริ่มต้นจากนั้นข้าม 64 บิตเพื่อไปยังองค์ประกอบที่ 3 การรู้ว่าต้องข้ามไปกี่บิตคือสิ่งที่ทำให้อาร์เรย์เร็วรู้ว่ากี่บิตที่จะกระโดดข้ามเป็นสิ่งที่ทำให้อาร์เรย์รวดเร็ว

['hello', 'i', 'am', 'a', 'banana']ตอนนี้พิจารณาลำดับของสตริง สตริงคือวัตถุที่มีขนาดแตกต่างกันไปดังนั้นหากคุณพยายามจัดเก็บไว้ในบล็อกหน่วยความจำที่อยู่ติดกันมันจะออกมาในลักษณะนี้

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

ตอนนี้คอมพิวเตอร์ของคุณไม่มีวิธีที่รวดเร็วในการเข้าถึงองค์ประกอบที่ขอแบบสุ่ม กุญแจสำคัญในการเอาชนะสิ่งนี้คือการใช้พอยน์เตอร์ โดยทั่วไปให้เก็บแต่ละสตริงในตำแหน่งหน่วยความจำแบบสุ่มและเติมอาร์เรย์ด้วยที่อยู่หน่วยความจำของแต่ละสตริง (ที่อยู่หน่วยความจำเป็นเพียงจำนวนเต็ม) ตอนนี้สิ่งต่างๆจะเป็นเช่นนี้

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

ตอนนี้ถ้าคุณขอให้คอมพิวเตอร์ของคุณดึงองค์ประกอบที่ 3 เหมือนก่อนหน้านี้มันสามารถข้ามผ่าน 64 บิตได้ (สมมติว่าที่อยู่หน่วยความจำเป็นจำนวนเต็ม 32 บิต) จากนั้นทำขั้นตอนเพิ่มเติมอีกหนึ่งขั้นเพื่อดึงข้อมูลสตริง

ความท้าทายสำหรับ NumPy คือไม่มีการรับประกันว่าพอยน์เตอร์จะชี้ไปที่สตริงจริงๆ นั่นเป็นเหตุผลที่รายงาน dtype เป็น 'object'

จะเสียบหลักสูตรของตัวเองใน NumPy อย่างไร้ยางอายซึ่งในตอนแรกฉันพูดถึงเรื่องนี้


เขียนได้ดี.. ขอบคุณ
tedd

8

คำตอบที่ได้รับการยอมรับเป็นสิ่งที่ดี แค่อยากจะให้คำตอบซึ่งอ้างอิงเอกสาร เอกสารระบุว่า:

Pandas ใช้อ็อบเจ็กต์ dtype สำหรับจัดเก็บสตริง

อย่างที่ความเห็นนำบอกว่า "อย่ากังวลไปเลยมันควรจะเป็นแบบนี้" (แม้ว่าคำตอบที่ยอมรับจะช่วยอธิบาย "ทำไม" ได้ดี แต่สตริงมีความยาวผันแปรได้)

แต่สำหรับสตริงความยาวของสตริงจะไม่คงที่


เหตุใดฉันจึงต้องแปลงทุกคอลัมน์ที่ฉันส่งผ่านเป็น scipy หรือ sklearn astype (str) เพื่อให้ยอมรับได้ ดูเหมือนว่าฉันควรจะใช้สิ่งนั้นกับคอลัมน์ทั้งหมดได้ในตอนแรก
Tinkinc

ฉันไม่เข้าใจ; @Tinkinc จะเกิดอะไรขึ้นถ้าคุณไม่แปลงคอลัมน์เป็นสตริง? และคำตอบนี้ดูเหมือนจะเป็นวิธีที่ดีในการแปลงคอลัมน์ทั้งหมดastype(str)แม้ว่าฉันจะยังสงสัยว่าจำเป็นต้องมีการแปลงสตริงก็ตาม
The Red Pea

ฉันไม่สามารถเติม (0) วัตถุทั้งหมดในการอยู่ในกรอบข้อมูลของฉัน (1, น่าน) แทนที่จะเป็น (1,0)
Tinkinc

ขอโทษ @Tinkinc ฉันยังไม่เข้าใจ; ฉันต้องการความช่วยเหลือ แต่ปัญหาของคุณฟังดูซับซ้อนกว่าความคิดเห็นใน Stack Overflow ลองถามคำถามหรือเข้าร่วมแชทกับฉัน (แค่เชิญคุณ)
The Red Pea

3

ในเวอร์ชัน 1.0.0 (มกราคม 2020) แพนด้าได้เปิดตัวเป็นฟีเจอร์ทดลองที่ให้การสนับสนุนระดับเฟิร์สคลาสสำหรับประเภทสตริงผ่าน pandas.StringDtypeหมีแพนด้าได้แนะนำเป็นคุณลักษณะทดลองให้การสนับสนุนชั้นแรกประเภทสตริงผ่าน

ในขณะที่คุณยังจะได้เห็นobjectโดยค่าเริ่มต้นชนิดใหม่ที่สามารถนำมาใช้โดยการระบุdtypeของpd.StringDtypeหรือเพียงแค่'string':

>>> pd.Series(['abc', None, 'def'])
0     abc
1    None
2     def
dtype: object
>>> pd.Series(['abc', None, 'def'], dtype=pd.StringDtype())
0     abc
1    <NA>
2     def
dtype: string
>>> pd.Series(['abc', None, 'def']).astype('string')
0     abc
1    <NA>
2     def
dtype: string

2
อย่าใช้สิ่งนี้ .... แต่. ตามที่ระบุไว้The implementation may change without warning.ซึ่งหมายความว่าการอัปเดตใหม่จะทำให้โปรแกรมเก่าของคุณเสียหาย
NoName

1
นั่นขึ้นอยู่กับว่าคุณจะใช้มันเพื่ออะไร หากคุณต้องการใช้ในระบบการผลิตที่จำเป็นต้องมีการอัปเกรดแพ็กเกจอย่างต่อเนื่องและเมื่อใดที่ API ขาดทำให้เกิดภาระการบำรุงรักษาที่ยอมรับไม่ได้ให้ใส่ใจกับคำว่า "ทดลอง" แต่ถ้าคุณใช้แพนด้าเพื่อทำการสำรวจ การวิเคราะห์ในสคริปต์ที่เวลาชีวิตไม่เพิ่มขึ้นในวันทำงานความกังวลเหล่านั้นน่าจะมีความหมายกับคุณเพียงเล็กน้อย
fuglede

1
สำหรับ Pandas 1.1 API ดูเหมือนว่าจะเสถียรdtypes ทั้งหมดสามารถแปลงเป็น StringDtypeได้แล้ว
D3f0
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.