แปลงคอลัมน์เป็นสตริงใน Pandas


179

ฉันมี DataFrame ต่อไปนี้จากแบบสอบถาม SQL:

(Pdb) pp total_rows
     ColumnID  RespondentCount
0          -1                2
1  3030096843                1
2  3030096845                1

และฉันต้องการหมุนมันเช่นนี้

total_data = total_rows.pivot_table(cols=['ColumnID'])

(Pdb) pp total_data
ColumnID         -1            3030096843   3030096845
RespondentCount            2            1            1

[1 rows x 3 columns]


total_rows.pivot_table(cols=['ColumnID']).to_dict('records')[0]

{3030096843: 1, 3030096845: 1, -1: 2}

แต่ฉันต้องการตรวจสอบให้แน่ใจว่ามีการโยนคอลัมน์ 303 รายการเป็นสตริงแทนที่จะเป็นจำนวนเต็มเพื่อที่ฉันจะได้รับสิ่งนี้:

{'3030096843': 1, '3030096845': 1, -1: 2}

จากนุ่น 1.0 เอกสารแนะนำให้ใช้astype("string")แทนastype(str)ด้วยเหตุผลที่ดีบ้างลองดู
cs95

คำตอบ:


332

วิธีหนึ่งในการแปลงเป็นสตริงคือใช้astype :

total_rows['ColumnID'] = total_rows['ColumnID'].astype(str)

อย่างไรก็ตามบางทีคุณกำลังมองหาto_jsonฟังก์ชั่นซึ่งจะแปลงคีย์ให้เป็น json ที่ถูกต้อง

In [11]: df = pd.DataFrame([['A', 2], ['A', 4], ['B', 6]])

In [12]: df.to_json()
Out[12]: '{"0":{"0":"A","1":"A","2":"B"},"1":{"0":2,"1":4,"2":6}}'

In [13]: df[0].to_json()
Out[13]: '{"0":"A","1":"A","2":"B"}'

หมายเหตุ: คุณสามารถผ่านในบัฟเฟอร์ / ไฟล์เพื่อบันทึกสิ่งนี้ไปพร้อมกับตัวเลือกอื่น ๆ ...


3
ฉันคิดว่า to_string () ดีกว่าเนื่องจากการเก็บรักษา NULLs stackoverflow.com/a/44008334/3647167
Keith

1
@ Keith null อนุรักษ์เป็นที่น่าสนใจ แต่หมอบอกว่าจุดประสงค์ของมันคือ 'ทำให้ DataFrame ส่งออกไปยังตารางที่เป็นมิตรกับคอนโซล' ฉันต้องการใครสักคนที่มีอำนาจในการชั่งน้ำหนัก
3pitt

to_json()อาจไม่เรียกใช้astype(str)เนื่องจากปล่อย datetime64 และคลาสย่อยเป็นมิลลิวินาทีนับตั้งแต่ยุค
Sussch

1
@Sussch ฉันสงสัยว่าเป็นเพราะ json ไม่มีรูปแบบวันที่และเวลาที่ชัดเจนดังนั้นคุณถูกบังคับให้ใช้ยุค ซึ่งก็คือการพูดฉันคิดว่านั่นเป็นมาตรฐาน
Andy Hayden

49

หากคุณต้องการแปลงคอลัมน์ทั้งหมดเป็นสตริงคุณสามารถใช้:

df = df.astype(str)

สิ่งนี้มีประโยชน์หากคุณต้องการทุกอย่างยกเว้นคอลัมน์สองสามรายการที่จะเป็นสตริง / วัตถุจากนั้นย้อนกลับไปและแปลงคอลัมน์อื่นเป็นสิ่งที่คุณต้องการ (จำนวนเต็มในกรณีนี้):

 df[["D", "E"]] = df[["D", "E"]].astype(int) 

28

ต่อไปนี้เป็นอีกคอลัมน์หนึ่งที่มีประโยชน์อย่างยิ่งในการ แปลงหลายคอลัมน์เป็นสตริงแทนที่จะเป็นคอลัมน์เดียว:

In [76]: import numpy as np
In [77]: import pandas as pd
In [78]: df = pd.DataFrame({
    ...:     'A': [20, 30.0, np.nan],
    ...:     'B': ["a45a", "a3", "b1"],
    ...:     'C': [10, 5, np.nan]})
    ...: 

In [79]: df.dtypes ## Current datatype
Out[79]: 
A    float64
B     object
C    float64
dtype: object

## Multiple columns string conversion
In [80]: df[["A", "C"]] = df[["A", "C"]].astype(str) 

In [81]: df.dtypes ## Updated datatype after string conversion
Out[81]: 
A    object
B    object
C    object
dtype: object


0

pandas> = 1.0: ได้เวลาหยุดแล้วastype(str)!

ก่อนที่จะมีนุ่น 1.0 (จริง ๆ แล้ว 0.25) นี่เป็นวิธีการแยกแยะในการประกาศซีรี่ส์ / คอลัมน์เป็นสตริง:

# pandas <= 0.25
# Note to pedants: specifying the type is unnecessary since pandas will 
# automagically infer the type as object
s = pd.Series(['a', 'b', 'c'], dtype=str)
s.dtype
# dtype('O')

ตั้งแต่ pandas 1.0 เป็นต้นไปให้พิจารณาใช้"string"typeแทน

# pandas >= 1.0
s = pd.Series(['a', 'b', 'c'], dtype="string")
s.dtype
# StringDtype

นี่คือเหตุผลที่อ้างถึงโดยเอกสาร:

  1. คุณสามารถจัดเก็บส่วนผสมของสตริงและสตริงที่ไม่ได้ตั้งใจในอาร์เรย์ dtype ของวัตถุ มันจะดีกว่าถ้ามี dtype เฉพาะ

  2. objectการดำเนินงานแบ่ง dtype dtype DataFrame.select_dtypes()เฉพาะเช่น ไม่มีวิธีที่ชัดเจนในการเลือกข้อความเพียงอย่างเดียวในขณะที่ยกเว้นคอลัมน์ที่ไม่ใช่ข้อความ แต่ยังคงเป็นประเภทวัตถุ

  3. เมื่ออ่านรหัสเนื้อหาของobjectอาร์เรย์ dtype 'string'มีความชัดเจนน้อยกว่า

ดูเพิ่มเติมส่วนที่เกี่ยวกับความแตกต่างระหว่างพฤติกรรม"string"objectและ

ส่วนขยายประเภท (แนะนำใน 0.24 และเป็นทางการใน 1.0) อยู่ใกล้กับหมีแพนด้ามากกว่าก้อนซึ่งเป็นสิ่งที่ดีเพราะประเภทก้อนไม่มีพลังเพียงพอ ตัวอย่างเช่น NumPy ไม่มีวิธีใด ๆ ในการแสดงข้อมูลที่ขาดหายไปในข้อมูลจำนวนเต็ม (ตั้งแต่type(NaN) == float) แต่นุ่นสามารถใช้คอลัมน์ Nullable Integerได้


เหตุใดฉันจึงควรหยุดใช้

การผสม dtypes
โดยบังเอิญเหตุผลแรกที่อธิบายไว้ในเอกสารคือคุณสามารถจัดเก็บข้อมูลที่ไม่ใช่ข้อความในคอลัมน์วัตถุโดยไม่ได้ตั้งใจ

# pandas <= 0.25
pd.Series(['a', 'b', 1.23])   # whoops, this should have been "1.23"

0       a
1       b
2    1.23
dtype: object

pd.Series(['a', 'b', 1.23]).tolist()
# ['a', 'b', 1.23]   # oops, pandas was storing this as float all the time.
# pandas >= 1.0
pd.Series(['a', 'b', 1.23], dtype="string")

0       a
1       b
2    1.23
dtype: string

pd.Series(['a', 'b', 1.23], dtype="string").tolist()
# ['a', 'b', '1.23']   # it's a string and we just averted some potentially nasty bugs.

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

พิจารณา,

# Setup
df = pd.DataFrame({'A': ['a', 'b', 'c'], 'B': [{}, [1, 2, 3], 123]})
df
 
   A          B
0  a         {}
1  b  [1, 2, 3]
2  c        123

เมื่อถึงหมีแพนด้า 0.25, ไม่มีทางที่จะแยกแยะว่า "A" และ "B" ไม่มีข้อมูลประเภทเดียวกัน

# pandas <= 0.25  
df.dtypes

A    object
B    object
dtype: object

df.select_dtypes(object)

   A          B
0  a         {}
1  b  [1, 2, 3]
2  c        123

จากแพนด้า 1.0 สิ่งนี้ง่ายกว่ามาก:

# pandas >= 1.0
# Convenience function I call to help illustrate my point.
df = df.convert_dtypes()
df.dtypes

A    string
B    object
dtype: object

df.select_dtypes("string")

   A
0  a
1  b
2  c

ความสามารถในการอ่าน
นี่คือการอธิบายตนเอง ;-)


ตกลงฉันควรหยุดใช้ทันทีหรือไม่

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


-1

ใช้.apply()กับlambdaฟังก์ชั่นการแปลงยังทำงานได้ในกรณีนี้:

total_rows['ColumnID'] = total_rows['ColumnID'].apply(lambda x: str(x))

สำหรับดาต้าเฟรมทั้งหมดที่คุณสามารถ.applymap()ใช้ได้ (แต่ในกรณีใด ๆ อาจ.astype()จะเร็วกว่า)

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