แปลงคอลัมน์ Pandas ที่มี NaN เป็น dtype` int`


175

ฉันอ่านข้อมูลจากไฟล์. csv ไปยังดาต้าดาต้าเฟรมของ Pandas ดังนี้ สำหรับคอลัมน์ใดคอลัมน์หนึ่งคือผมต้องการที่จะระบุชนิดคอลัมน์เป็นid intปัญหาคือidซีรีส์มีค่าหายไป / ว่างเปล่า

เมื่อฉันพยายามที่จะโยนidคอลัมน์เป็นจำนวนเต็มในขณะที่อ่าน. csv ฉันได้รับ:

df= pd.read_csv("data.csv", dtype={'id': int}) 
error: Integer column has NA values

อีกทางหนึ่งฉันพยายามแปลงประเภทคอลัมน์หลังจากอ่านด้านล่าง แต่ครั้งนี้ฉันได้รับ:

df= pd.read_csv("data.csv") 
df[['id']] = df[['id']].astype(int)
error: Cannot convert NA to integer

ฉันจะจัดการสิ่งนี้ได้อย่างไร


3
ฉันคิดว่าค่าจำนวนเต็มไม่สามารถแปลงหรือเก็บไว้ในซีรีส์ / dataframe หากไม่มีค่า / NaN นี้ผมคิดว่าเป็นจะทำอย่างไรกับความเข้ากันได้ numpy (ฉันคาดเดาที่นี่) หากคุณต้องการความเข้ากันได้หายไปมูลค่าแล้วฉันจะเก็บค่าเป็นลอย
EdChum

1
ดูที่นี่: pandas.pydata.org/pandas-docs/dev/… ; คุณต้องมีลอย dtype เมื่อคุณมีค่าที่หายไป (หรือในทางเทคนิควัตถุ dtype แต่ที่ไม่มีประสิทธิภาพ); เป้าหมายในการใช้งานประเภท int คืออะไร
Jeff

6
ฉันเชื่อว่านี่เป็นปัญหา NumPy ไม่ใช่เฉพาะ Pandas มันเป็นความอัปยศเนื่องจากมีหลายกรณีเมื่อมีชนิด int ที่ช่วยให้ความเป็นไปได้ของค่า Null มีประสิทธิภาพมากขึ้นกว่าคอลัมน์ลอยขนาดใหญ่
ely

1
ฉันมีปัญหากับสิ่งนี้เช่นกัน ฉันมีหลาย dataframes ที่ฉันต้องการผสานตามการแสดงสตริงของคอลัมน์ "จำนวนเต็ม" หลาย ๆ อย่างไรก็ตามเมื่อหนึ่งในคอลัมน์จำนวนเต็มเหล่านั้นมี np.nan การคัดเลือกสตริงจะสร้าง ".0" ซึ่งจะปิดการผสาน เพียงแค่ทำให้สิ่งต่าง ๆ มีความซับซ้อนขึ้นเล็กน้อยจะดีถ้ามีการทำงานที่เรียบง่าย
dermen

1
@Rhubarb, การสนับสนุนตัวเลือก Nullable Integer ได้เพิ่มเข้ามาอย่างเป็นทางการใน pandas 0.24.0 - ในที่สุด :) - โปรดค้นหาคำตอบที่ได้รับการปรับปรุง pandas 0.24.x บันทึกประจำรุ่น
mork

คำตอบ:


169

การขาดน่านตัวแทนในคอลัมน์จำนวนเต็มเป็นหมีแพนด้า "gotcha"

วิธีแก้ปัญหาตามปกติคือเพียงแค่ใช้ลอย


13
มีวิธีแก้ไขอื่น ๆ อีกไหมนอกจากรักษาพวกมันเหมือนลอยตัว?
NumenorForLife

3
@ jsc123 คุณสามารถใช้วัตถุ dtype สิ่งนี้มาพร้อมกับการเตือนสุขภาพเล็กน้อย แต่ส่วนใหญ่ทำงานได้ดี
Andy Hayden

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

29
ใน v0.24 ตอนนี้คุณสามารถทำdf = df.astype(pd.Int32Dtype())(การแปลง dataFrame df['col'] = df['col'].astype(pd.Int32Dtype())ทั้งหมดหรือ) ได้รับการยอมรับอื่น ๆ ประเภทจำนวนเต็ม nullable มีและpd.Int16Dtype pd.Int64Dtypeเลือกพิษของคุณ
cs95

1
เป็นค่า NaN แต่การตรวจสอบ isnan ไม่ทำงานเลย :(
Winston

117

ในเวอร์ชั่น 0.24. + pandas ได้รับความสามารถในการเก็บจำนวนเต็มชนิดที่มีค่าที่ขาดหายไป

Nullable จำนวนเต็มชนิดข้อมูล

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

arr = pd.array([1, 2, np.nan], dtype=pd.Int64Dtype())
pd.Series(arr)

0      1
1      2
2    NaN
dtype: Int64

สำหรับการแปลงคอลัมน์เป็นจำนวนเต็ม null ใช้:

df['myCol'] = df['myCol'].astype('Int64')

4
ฉันชอบคำตอบนี้
cs95

8
โปรดทราบว่า dtype ต้องเป็น"Int64"และไม่ใช่"int64"(แรกต้องเป็นตัวพิมพ์ใหญ่ 'i')
Viacheslav Z

2
df.myCol = df.myCol.astype('Int64')หรือdf['myCol'] = df['myCol'].astype('Int64')
LoMaPh

43

กรณีการใช้งานของฉันกำลังบันทึกข้อมูลก่อนที่จะโหลดลงในตารางฐานข้อมูล:

df[col] = df[col].fillna(-1)
df[col] = df[col].astype(int)
df[col] = df[col].astype(str)
df[col] = df[col].replace('-1', np.nan)

ลบ NaNs, แปลงเป็น int, แปลงเป็น str แล้วใส่ NAN อีกครั้ง

มันไม่สวย แต่ทำให้งานเสร็จ!


1
ฉันดึงผมออกมาแล้วพยายามโหลดหมายเลขซีเรียลที่มีค่าเป็นโมฆะและที่เหลือเป็นแบบลอยนี่ช่วยฉันได้
Chris Decker

1
OP ต้องการคอลัมน์จำนวนเต็ม การแปลงเป็นสตริงไม่เป็นไปตามเงื่อนไข
Rishab Gupta

1
ทำงานได้เฉพาะในกรณีที่ col ไม่ได้มี -1 มิฉะนั้นมันจะยุ่งกับข้อมูล
Sharvari Gc

ถ้าเช่นนั้นจะกลับไปที่ int ได้อย่างไร?
abdoulsn

5

ตอนนี้เป็นไปได้ที่จะสร้างคอลัมน์หมีแพนด้าที่มี NaNs เป็น dtype intเนื่องจากขณะนี้มีการเพิ่มอย่างเป็นทางการในแพนด้า 0.24.0

บันทึกย่อประจำรุ่น pandas 0.24.x ข้อความอ้างอิง: " Pandas ได้รับความสามารถในการเก็บจำนวนเต็มจำนวนเต็มด้วยค่าที่หายไป


4

หากคุณต้องการรวมจำนวนเต็มและ NaN ในคอลัมน์อย่างแน่นอนคุณสามารถใช้ชนิดข้อมูล 'วัตถุ':

df['col'] = (
    df['col'].fillna(0)
    .astype(int)
    .astype(object)
    .where(df['col'].notnull())
)

สิ่งนี้จะแทนที่ NaNs ด้วยจำนวนเต็ม (ไม่สำคัญว่า) แปลงเป็น int แปลงเป็นวัตถุและใส่ NaN อีกครั้ง


3

idหากคุณสามารถปรับเปลี่ยนการจัดเก็บข้อมูลของคุณให้ใช้ค่าแมวมองที่หายไป กรณีการใช้งานทั่วไปสรุปโดยชื่อคอลัมน์เนื่องจากidเป็นจำนวนเต็มมากกว่าศูนย์อย่างเคร่งครัดคุณสามารถใช้0เป็นค่าเฝ้ายามเพื่อให้คุณสามารถเขียน

if row['id']:
   regular_process(row)
else:
   special_process(row)

3

คุณสามารถใช้.dropna()หากตกลงเพื่อวางแถวด้วยค่า NaN

df = df.dropna(subset=['id'])

หรือใช้.fillna()และ.astype()เพื่อแทนที่ NaN ด้วยค่าและแปลงเป็น int

ฉันพบปัญหานี้เมื่อประมวลผลไฟล์ CSV ด้วยจำนวนเต็มขนาดใหญ่ในขณะที่บางส่วนหายไป (NaN) การใช้ float เป็นประเภทไม่ใช่ตัวเลือกเพราะฉันอาจสูญเสียความแม่นยำ

วิธีการแก้ปัญหาของฉันคือการใช้ STR เป็นชนิดกลาง จากนั้นคุณสามารถแปลงสตริงเป็น int ตามที่คุณต้องการในภายหลังในรหัส ฉันแทนที่ NaN ด้วย 0 แต่คุณสามารถเลือกค่าใดก็ได้

df = pd.read_csv(filename, dtype={'id':str})
df["id"] = df["id"].fillna("0").astype(int)

สำหรับภาพประกอบนี่เป็นตัวอย่างว่าการลอยอาจหลุดความแม่นยำได้อย่างไร:

s = "12345678901234567890"
f = float(s)
i = int(f)
i2 = int(s)
print (f, i, i2)

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

1.2345678901234567e+19 12345678901234567168 12345678901234567890

2

วิธีแก้ปัญหาส่วนใหญ่ที่นี่จะบอกวิธีใช้จำนวนเต็มตัวยึดเพื่อแสดงค่าเป็นโมฆะ วิธีการดังกล่าวไม่เป็นประโยชน์หากคุณไม่แน่ใจว่าจำนวนเต็มจะไม่ปรากฏในแหล่งข้อมูลของคุณ วิธีการของฉันด้วยจะจัดรูปแบบลอยโดยไม่มีค่าทศนิยมและแปลงค่า Null เป็น None ผลที่ได้คือประเภทข้อมูลวัตถุที่จะมีลักษณะเหมือนเขตข้อมูลจำนวนเต็มที่มีค่าเป็นศูนย์เมื่อโหลดลงใน CSV

keep_df[col] = keep_df[col].apply(lambda x: None if pandas.isnull(x) else '{0:.0f}'.format(pandas.to_numeric(x)))

1

ฉันพบปัญหาในการทำงานกับ pyspark เนื่องจากนี่เป็นส่วนหน้าของไพ ธ อนสำหรับโค้ดที่รันบน jvm จึงต้องการความปลอดภัยของประเภทและการใช้ float แทน int ไม่ใช่ตัวเลือก ฉันแก้ไขปัญหาด้วยการห่อหมีแพนด้าpd.read_csvในฟังก์ชั่นที่จะเติมคอลัมน์ที่ผู้ใช้กำหนดด้วยค่าการเติมที่ผู้ใช้กำหนดก่อนที่จะส่งไปยังประเภทที่ต้องการ นี่คือสิ่งที่ฉันใช้:

def custom_read_csv(file_path, custom_dtype = None, fill_values = None, **kwargs):
    if custom_dtype is None:
        return pd.read_csv(file_path, **kwargs)
    else:
        assert 'dtype' not in kwargs.keys()
        df = pd.read_csv(file_path, dtype = {}, **kwargs)
        for col, typ in custom_dtype.items():
            if fill_values is None or col not in fill_values.keys():
                fill_val = -1
            else:
                fill_val = fill_values[col]
            df[col] = df[col].fillna(fill_val).astype(typ)
    return df

1
import pandas as pd

df= pd.read_csv("data.csv")
df['id'] = pd.to_numeric(df['id'])

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

ในขณะที่รหัสนี้อาจแก้ไขปัญหาของ OP ได้ดีที่สุดคือการรวมคำอธิบายเกี่ยวกับวิธีการ / ทำไมรหัสของคุณที่อยู่มัน ด้วยวิธีนี้ผู้เข้าชมในอนาคตสามารถเรียนรู้จากโพสต์ของคุณและนำไปใช้กับรหัสของตนเอง ดังนั้นไม่ใช่บริการการเข้ารหัส แต่เป็นแหล่งความรู้ นอกจากนี้คุณภาพสูงและคำตอบที่สมบูรณ์มีแนวโน้มที่จะถูกถอนออก คุณสมบัติเหล่านี้พร้อมกับความต้องการที่โพสต์ทั้งหมดมีอยู่ในตัวเองเป็นจุดแข็งของ SO ในขณะที่แพลตฟอร์มแตกต่างจากฟอรัม คุณสามารถeditเพิ่มข้อมูลเพิ่มเติม & / หรือเสริมคำอธิบายของคุณด้วยเอกสารต้นฉบับ
SherylHohman

0

ก่อนอื่นให้ลบแถวที่มี NaN จากนั้นทำการแปลงจำนวนเต็มในแถวที่เหลือ ที่แทรกแถวที่ลบล่าสุดอีกครั้ง หวังว่ามันจะทำงาน


-1

สมมติว่า DateColumn ที่จัดรูปแบบของคุณ 3312018.0 ควรแปลงเป็น 03/31/2018 เป็นสตริง และบางระเบียนหายไปหรือ 0

df['DateColumn'] = df['DateColumn'].astype(int)
df['DateColumn'] = df['DateColumn'].astype(str)
df['DateColumn'] = df['DateColumn'].apply(lambda x: x.zfill(8))
df.loc[df['DateColumn'] == '00000000','DateColumn'] = '01011980'
df['DateColumn'] = pd.to_datetime(df['DateColumn'], format="%m%d%Y")
df['DateColumn'] = df['DateColumn'].apply(lambda x: x.strftime('%m/%d/%Y'))
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.