วิธีตรวจสอบ dtype ของคอลัมน์ใน python panda


135

ฉันจำเป็นต้องใช้ฟังก์ชันต่างๆเพื่อจัดการคอลัมน์ตัวเลขและคอลัมน์สตริง สิ่งที่ฉันทำตอนนี้มันโง่จริงๆ:

allc = list((agg.loc[:, (agg.dtypes==np.float64)|(agg.dtypes==np.int)]).columns)
for y in allc:
    treat_numeric(agg[y])    

allc = list((agg.loc[:, (agg.dtypes!=np.float64)&(agg.dtypes!=np.int)]).columns)
for y in allc:
    treat_str(agg[y])    

มีวิธีที่หรูหรากว่านี้ไหม? เช่น

for y in agg.columns:
    if(dtype(agg[y]) == 'string'):
          treat_str(agg[y])
    elif(dtype(agg[y]) != 'string'):
          treat_numeric(agg[y])

2
stringไม่ใช่ dtype
David Robinson

คำตอบ:


124

คุณสามารถเข้าถึงชนิดข้อมูลของคอลัมน์ด้วยdtype:

for y in agg.columns:
    if(agg[y].dtype == np.float64 or agg[y].dtype == np.int64):
          treat_numeric(agg[y])
    else:
          treat_str(agg[y])

1
สวัสดีเดวิดคุณสามารถแสดงความคิดเห็นว่าทำไมคุณถึงรวม == np.float64 เราไม่ได้พยายามที่จะแปลงเป็นลอย? ขอบคุณ
Ryan Chase

@RyanChase OP ในคำถามนี้ไม่เคยบอกว่าเขากำลังแปลงเป็นลอยเขาแค่ต้องรู้ว่าจะใช้treat_numericฟังก์ชัน(ไม่ระบุ) หรือไม่ เนื่องจากเขารวมagg.dtypes==np.float64เป็นตัวเลือกฉันก็ทำเช่นกัน
David Robinson

3
มีตัวเลขมากกว่าสองประเภทนี้ทุกอย่างอยู่numberที่นี่: docs.scipy.org/doc/numpy-1.13.0/reference/arrays.scalars.htmlวิธีแก้ปัญหาทั่วไปคือis_numeric_dtype(agg[y])
Attila Tanyi

96

ในpandas 0.20.2คุณสามารถทำได้:

from pandas.api.types import is_string_dtype
from pandas.api.types import is_numeric_dtype

is_string_dtype(df['A'])
>>>> True

is_numeric_dtype(df['B'])
>>>> True

ดังนั้นรหัสของคุณจึงกลายเป็น:

for y in agg.columns:
    if (is_string_dtype(agg[y])):
        treat_str(agg[y])
    elif (is_numeric_dtype(agg[y])):
        treat_numeric(agg[y])

1
มีทางเลือกอื่นสำหรับแพนด้ารุ่นเก่าหรือไม่? ฉันได้รับข้อผิดพลาด: ไม่มีโมดูลชื่อ api.types
rph

2
pandas.core.common.is_numeric_dtypeมีอยู่ตั้งแต่ Pandas 0.13 และมันก็ทำแบบเดียวกัน แต่มันถูกเลิกใช้pandas.api.types.is_numeric_dtypeใน 0.19 ฉันคิดว่า
Migwell

เป็นคำตอบที่เป็นธรรมชาติที่สุด แต่ควรทราบข้อควรระวังบางประการที่นี่
BeforeFlight

46

ฉันรู้ว่านี่เป็นกระทู้เก่าเล็กน้อย แต่ด้วยแพนด้า 19.02 คุณสามารถทำได้:

df.select_dtypes(include=['float64']).apply(your_function)
df.select_dtypes(exclude=['string','object']).apply(your_other_function)

http://pandas.pydata.org/pandas-docs/version/0.19.2/generated/pandas.DataFrame.select_dtypes.html


1
คำตอบที่ดีฉันอาจจะทำinclude[np.number](รวม ints และ 32 bit float) สำหรับบรรทัดแรกและexclude[object]สำหรับบรรทัดที่สอง สตริงเป็นวัตถุเท่าที่เกี่ยวข้องกับ dtypes ในความเป็นจริงการรวม 'สตริง' กับวัตถุทำให้ฉันมีข้อผิดพลาด
JohnE

1
ดูเหมือนว่าจะไม่รองรับ "string" อีกต่อไปต้องใช้ "object" แทน แต่คำตอบที่ถูกต้องแน่นอน :)
Bertrand

ควรสังเกตด้วยว่า'period'dtype กำลังเพิ่มขึ้นNotImplementedErrorในขณะนี้ (แพนด้า 0.24.2) ดังนั้นอาจต้องมีการประมวลผลหลังการทำด้วยมือ
BeforeFlight

22

ชื่อคำถามที่ถามเป็นเรื่องทั่วไป แต่ผู้เขียนใช้กรณีที่ระบุไว้ในเนื้อหาของคำถามนั้นเฉพาะเจาะจง ดังนั้นอาจใช้คำตอบอื่น ๆ

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

1. เปรียบเทียบประเภทโดยตรงผ่าน==(คำตอบที่ยอมรับ)

แม้ว่าจะเป็นคำตอบที่ยอมรับและมีการโหวตมากที่สุด แต่ฉันคิดว่าไม่ควรใช้วิธีนี้เลย เพราะในความเป็นจริงวิธีนี้ท้อแท้ในหลามตามที่กล่าวไว้หลายครั้งที่นี่
แต่ถ้ายังคงต้องการที่จะใช้มัน - ควรจะตระหนักถึงบาง dtypes หมีแพนด้าที่เฉพาะเจาะจงเช่นpd.CategoricalDType, หรือpd.PeriodDtype pd.IntervalDtypeที่นี่ต้องใช้พิเศษtype( )เพื่อที่จะจดจำ dtype ได้อย่างถูกต้อง:

s = pd.Series([pd.Period('2002-03','D'), pd.Period('2012-02-01', 'D')])
s
s.dtype == pd.PeriodDtype   # Not working
type(s.dtype) == pd.PeriodDtype # working 

>>> 0    2002-03-01
>>> 1    2012-02-01
>>> dtype: period[D]
>>> False
>>> True

ข้อแม้อีกประการหนึ่งคือควรระบุประเภทอย่างแม่นยำ:

s = pd.Series([1,2])
s
s.dtype == np.int64 # Working
s.dtype == np.int32 # Not working

>>> 0    1
>>> 1    2
>>> dtype: int64
>>> True
>>> False

2. isinstance()แนวทาง

วิธีนี้ยังไม่ได้รับการกล่าวถึงในคำตอบ

ดังนั้นหากเปรียบเทียบโดยตรงของประเภทที่ไม่ได้เป็นความคิดที่ดี - ช่วยให้ลองฟังก์ชั่นหลามเพื่อวัตถุประสงค์นี้คือ isinstance()-
มันล้มเหลวในตอนเริ่มต้นเนื่องจากสมมติว่าเรามีวัตถุบางอย่าง แต่pd.Seriesหรือpd.DataFrameอาจใช้เป็นเพียงคอนเทนเนอร์เปล่าที่มีการกำหนดไว้ล่วงหน้าdtypeแต่ไม่มีวัตถุอยู่ในนั้น:

s = pd.Series([], dtype=bool)
s

>>> Series([], dtype: bool)

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

df = pd.DataFrame({'int': [12, 2], 'dt': [pd.Timestamp('2013-01-02'), pd.Timestamp('2016-10-20')]},
                  index = ['A', 'B'])
for col in df.columns:
    df[col].dtype, 'is_int64 = %s' % isinstance(df.loc['A', col], np.int64)

>>> (dtype('int64'), 'is_int64 = True')
>>> (dtype('<M8[ns]'), 'is_int64 = False')

จะทำให้เข้าใจผิดในกรณีของข้อมูลประเภทผสมในคอลัมน์เดียว:

df2 = pd.DataFrame({'data': [12, pd.Timestamp('2013-01-02')]},
                  index = ['A', 'B'])
for col in df2.columns:
    df2[col].dtype, 'is_int64 = %s' % isinstance(df2.loc['A', col], np.int64)

>>> (dtype('O'), 'is_int64 = False')

และสุดท้าย แต่ไม่ท้ายสุด - วิธีนี้ไม่สามารถจดจำCategorydtype ได้โดยตรง ตามที่ระบุไว้ในเอกสาร :

การส่งคืนรายการเดียวจากข้อมูลหมวดหมู่จะส่งคืนค่าด้วยไม่ใช่การจัดหมวดหมู่ของความยาว“ 1”

df['int'] = df['int'].astype('category')
for col in df.columns:
    df[col].dtype, 'is_int64 = %s' % isinstance(df.loc['A', col], np.int64)

>>> (CategoricalDtype(categories=[2, 12], ordered=False), 'is_int64 = True')
>>> (dtype('<M8[ns]'), 'is_int64 = False')

ดังนั้นวิธีนี้จึงใช้ไม่ได้เกือบ

3. df.dtype.kindแนวทาง

วิธีนี้อาจใช้ได้ผลกับการว่างเปล่าpd.Seriesหรือpd.DataFramesแต่มีปัญหาอื่น

ประการแรก - ไม่สามารถแตกต่างกันได้บางประเภท:

df = pd.DataFrame({'prd'  :[pd.Period('2002-03','D'), pd.Period('2012-02-01', 'D')],
                   'str'  :['s1', 's2'],
                   'cat'  :[1, -1]})
df['cat'] = df['cat'].astype('category')
for col in df:
    # kind will define all columns as 'Object'
    print (df[col].dtype, df[col].dtype.kind)

>>> period[D] O
>>> object O
>>> category O

ประการที่สองสิ่งที่เป็นจริงยังไม่ชัดเจนสำหรับฉันมันแม้ผลตอบแทนจากการ dtypes บางไม่มี

4. df.select_dtypesแนวทาง

นี่คือสิ่งที่เราต้องการเกือบทั้งหมด วิธีนี้ได้รับการออกแบบภายในแพนด้าเพื่อให้จัดการกับกรณีมุมส่วนใหญ่ที่กล่าวถึงก่อนหน้านี้ - DataFrames ว่างเปล่าแตกต่าง dtypes ที่เป็นตัวเลขหรือเฉพาะแพนด้าได้ดี มันทำงานได้ดีกับ dtype .select_dtypes('bool')เดียวเช่น อาจใช้สำหรับการเลือกกลุ่มคอลัมน์ตาม dtype:

test = pd.DataFrame({'bool' :[False, True], 'int64':[-1,2], 'int32':[-1,2],'float': [-2.5, 3.4],
                     'compl':np.array([1-1j, 5]),
                     'dt'   :[pd.Timestamp('2013-01-02'), pd.Timestamp('2016-10-20')],
                     'td'   :[pd.Timestamp('2012-03-02')- pd.Timestamp('2016-10-20'),
                              pd.Timestamp('2010-07-12')- pd.Timestamp('2000-11-10')],
                     'prd'  :[pd.Period('2002-03','D'), pd.Period('2012-02-01', 'D')],
                     'intrv':pd.arrays.IntervalArray([pd.Interval(0, 0.1), pd.Interval(1, 5)]),
                     'str'  :['s1', 's2'],
                     'cat'  :[1, -1],
                     'obj'  :[[1,2,3], [5435,35,-52,14]]
                    })
test['int32'] = test['int32'].astype(np.int32)
test['cat'] = test['cat'].astype('category')

ตามที่ระบุไว้ในเอกสาร :

test.select_dtypes('number')

>>>     int64   int32   float   compl   td
>>> 0      -1      -1   -2.5    (1-1j)  -1693 days
>>> 1       2       2    3.4    (5+0j)   3531 days

บนอาจคิดว่านี่เราเห็นครั้งแรกที่ไม่คาดคิด (ที่เคยเป็นสำหรับฉัน: คำถาม ) ผล - จะรวมเข้าออกTimeDelta DataFrameแต่ตามที่ได้รับคำตอบในทางตรงกันข้ามมันควรจะเป็นเช่นนั้น แต่เราต้องตระหนักถึงมัน โปรดทราบว่าbooldtype ถูกข้ามซึ่งอาจไม่เป็นที่ต้องการสำหรับบางคน แต่เนื่องจากboolและnumberอยู่ใน " subtrees " ของ numpy dtype ที่แตกต่างกัน ในกรณีที่มีบูลเราอาจใช้test.select_dtypes(['bool'])ที่นี่

ข้อ จำกัด ต่อไปของวิธีนี้คือสำหรับรุ่นปัจจุบันของหมีแพนด้า (0.24.2) รหัสนี้จะเพิ่มtest.select_dtypes('period')NotImplementedError

และอีกสิ่งหนึ่งคือไม่สามารถแตกต่างสตริงจากวัตถุอื่น ๆ :

test.select_dtypes('object')

>>>     str     obj
>>> 0    s1     [1, 2, 3]
>>> 1    s2     [5435, 35, -52, 14]

แต่นี่เป็นสิ่งแรกที่กล่าวถึงในเอกสารแล้ว และประการที่สอง - ไม่ใช่ปัญหาของวิธีนี้ แต่เป็นวิธีการจัดเก็บสตริงDataFrameไม่ได้เป็นปัญหาของวิธีการนี้ค่อนข้างสตริงวิธีที่ถูกเก็บไว้ใน แต่อย่างไรก็ตามกรณีนี้จะต้องมีการประมวลผลบางอย่าง

5 df.api.types.is_XXX_dtypeแนวทาง

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

นอกจากนี้อาจเป็นเรื่องส่วนตัว แต่วิธีการนี้ยังมีnumberการประมวลผลกลุ่ม dtypes ที่'มนุษย์เข้าใจได้' มากกว่าเมื่อเปรียบเทียบกับ.select_dtypes('number'):

for col in test.columns:
    if pd.api.types.is_numeric_dtype(test[col]):
        print (test[col].dtype)

>>> bool
>>> int64
>>> int32
>>> float64
>>> complex128

ไม่ใช่timedeltaและboolรวมอยู่ด้วย สมบูรณ์

ไปป์ไลน์ของฉันใช้ประโยชน์จากฟังก์ชันนี้อย่างแท้จริงในช่วงเวลานี้รวมถึงการประมวลผลหลังมืออีกเล็กน้อย

เอาท์พุต

หวังว่าผมสามารถที่จะโต้แย้งประเด็นหลัก - ว่าวิธีการที่กล่าวถึงทั้งหมดอาจจะใช้ แต่เพียงpd.DataFrame.select_dtypes()และpd.api.types.is_XXX_dtypeควรได้รับการพิจารณาจริงๆเป็นคนที่ใช้บังคับ


1
คำตอบที่ยอดเยี่ยมและมีสูตรดี :-)
Oliver

8

หากคุณต้องการทำเครื่องหมายประเภทของคอลัมน์ดาต้าเฟรมเป็นสตริงคุณสามารถทำได้:

df['A'].dtype.kind

ตัวอย่าง:

In [8]: df = pd.DataFrame([[1,'a',1.2],[2,'b',2.3]])
In [9]: df[0].dtype.kind, df[1].dtype.kind, df[2].dtype.kind
Out[9]: ('i', 'O', 'f')

คำตอบสำหรับรหัสของคุณ:

for y in agg.columns:
    if(agg[y].dtype.kind == 'f' or agg[y].dtype.kind == 'i'):
          treat_numeric(agg[y])
    else:
          treat_str(agg[y])

4

เพื่อพิมพ์ชนิดข้อมูลคอลัมน์อย่างสวยงาม

ในการตรวจสอบประเภทข้อมูลหลังตัวอย่างเช่นการนำเข้าจากไฟล์

def printColumnInfo(df):
    template="%-8s %-30s %s"
    print(template % ("Type", "Column Name", "Example Value"))
    print("-"*53)
    for c in df.columns:
        print(template % (df[c].dtype, c, df[c].iloc[1]) )

เอาต์พุตภาพประกอบ:

Type     Column Name                    Example Value
-----------------------------------------------------
int64    Age                            49
object   Attrition                      No
object   BusinessTravel                 Travel_Frequently
float64  DailyRate                      279.0
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.