dtypes muck เกิดขึ้นเมื่อขยับแกนหนึ่ง (คอลัมน์)


9

พิจารณา DataFrame df

df = pd.DataFrame(dict(A=[1, 2], B=['X', 'Y']))

df

   A  B
0  1  X
1  2  Y

ถ้าฉันเลื่อนตามaxis=0(ค่าเริ่มต้น)

df.shift()

     A    B
0  NaN  NaN
1  1.0    X

มันดันแถวทั้งหมดลงไปหนึ่งแถวตามที่คาดไว้

แต่เมื่อฉันเปลี่ยนไป axis=1

df.shift(axis=1)

    A    B
0 NaN  NaN
1 NaN  NaN

ทุกอย่างเป็นโมฆะเมื่อฉันคาดหวัง

     A  B
0  NaN  1
1  NaN  2

ฉันเข้าใจว่าทำไมสิ่งนี้จึงเกิดขึ้น สำหรับaxis=0Pandas คือการดำเนินงานคอลัมน์โดยคอลัมน์ที่แต่ละคอลัมน์เป็นหนึ่งเดียวdtypeและเมื่อขยับมีโปรโตคอลที่ชัดเจนเกี่ยวกับวิธีการจัดการกับNaNค่าที่แนะนำที่จุดเริ่มต้นหรือจุดสิ้นสุด แต่เมื่อขยับตามaxis=1เราแนะนำความคลุมเครือที่อาจเกิดขึ้นdtypeจากคอลัมน์หนึ่งไปยังคอลัมน์ถัดไป ในกรณีนี้ฉันพยายามบังคับint64ให้objectคอลัมน์หนึ่งและ Pandas ตัดสินใจที่จะลบล้างค่า

สิ่งนี้จะเป็นปัญหามากขึ้นเมื่อdtypesเป็นint64และfloat64

df = pd.DataFrame(dict(A=[1, 2], B=[1., 2.]))

df

   A    B
0  1  1.0
1  2  2.0

และสิ่งเดียวกันก็เกิดขึ้น

df.shift(axis=1)

    A   B
0 NaN NaN
1 NaN NaN

คำถามของฉัน

อะไรคือสิ่งที่ดีสำหรับตัวเลือกการสร้าง dataframe ที่เปลี่ยนไปตามaxis=1ค่าในซึ่งผลที่ได้เปลี่ยนและ dtypes?

สำหรับint64/ float64กรณีผลลัพธ์จะมีลักษณะดังนี้:

df_shifted

     A  B
0  NaN  1
1  NaN  2

และ

df_shifted.dtypes

A    object
B     int64
dtype: object

ตัวอย่างที่ครอบคลุมมากขึ้น

df = pd.DataFrame(dict(A=[1, 2], B=[1., 2.], C=['X', 'Y'], D=[4., 5.], E=[4, 5]))

df

   A    B  C    D  E
0  1  1.0  X  4.0  4
1  2  2.0  Y  5.0  5

ควรมีลักษณะเช่นนี้

df_shifted

     A  B    C  D    E
0  NaN  1  1.0  X  4.0
1  NaN  2  2.0  Y  5.0

df_shifted.dtypes

A     object
B      int64
C    float64
D     object
E    float64
dtype: object

ดูเหมือนว่าข้อผิดพลาดกับผมว่าเกิดอะไรขึ้นถ้าคุณทำ dtypes ของคอลัมน์ทั้งหมดobject?
EdChum

มันได้ผล. ฉันมีงานอยู่สองสามรอบแล้ว ฉันแค่กระตุ้นชุมชนสำหรับความคิดบางอย่าง
piRSquared

ฉันจะยื่นเรื่องนี้เป็นปัญหาอย่างน้อยก็ควรเสนอตัวเลือกสำหรับการโปรโมต dtype ให้กับ dtype แบบผสมเช่นobject
EdChum

ฉันจะทำตอนนี้
piRSquared

1
@ EdChum-ReinstateMonica รอสักครู่! การเปลี่ยนแปลงเกิดขึ้นมากกว่าblocks>. <ใช้สิ่งนี้แทนแล้วดูdf = pd.DataFrame(dict(A=[1, 2], B=[3., 4.], C=['X', 'Y'], D=[5., 6.], E=[7, 8], F=['W', 'Z']))
piRSquared

คำตอบ:


7

ปรากฎว่านุ่นเปลี่ยนไปบนบล็อกที่คล้ายกัน dtypes

กำหนดdfเป็น

df = pd.DataFrame(dict(
    A=[1, 2], B=[3., 4.], C=['X', 'Y'],
    D=[5., 6.], E=[7, 8], F=['W', 'Z']
))

df

#  i    f  o    f  i  o
#  n    l  b    l  n  b
#  t    t  j    t  t  j
#
   A    B  C    D  E  F
0  1  3.0  X  5.0  7  W
1  2  4.0  Y  6.0  8  Z

มันจะเลื่อนจำนวนเต็มไปยังคอลัมน์จำนวนเต็มถัดไปลอยไปยังคอลัมน์ลอยถัดไปและวัตถุไปยังคอลัมน์วัตถุถัดไป

df.shift(axis=1)

    A   B    C    D    E  F
0 NaN NaN  NaN  3.0  1.0  X
1 NaN NaN  NaN  4.0  2.0  Y

ฉันไม่รู้ว่าเป็นความคิดที่ดี แต่นั่นคือสิ่งที่เกิดขึ้น


แนวทาง

astype(object) เป็นครั้งแรก

dtypes = df.dtypes.shift(fill_value=object)
df_shifted = df.astype(object).shift(1, axis=1).astype(dtypes)

df_shifted

     A  B    C  D    E  F
0  NaN  1  3.0  X  5.0  7
1  NaN  2  4.0  Y  6.0  8

transpose

จะทำให้มัน object

dtypes = df.dtypes.shift(fill_value=object)
df_shifted = df.T.shift().T.astype(dtypes)

df_shifted

     A  B    C  D    E  F
0  NaN  1  3.0  X  5.0  7
1  NaN  2  4.0  Y  6.0  8

itertuples

pd.DataFrame([(np.nan, *t[1:-1]) for t in df.itertuples()], columns=[*df])

     A  B    C  D    E  F
0  NaN  1  3.0  X  5.0  7
1  NaN  2  4.0  Y  6.0  8

แม้ว่าฉันอาจจะทำเช่นนี้

pd.DataFrame([
    (np.nan, *t[:-1]) for t in
    df.itertuples(index=False, name=None)
], columns=[*df])

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

1
ฉันจะโพสต์ปัญหาหลังการประชุม
piRSquared

ถ้ามันเป็นstrdytpes ทั้งหมดมันก็ทำงานได้อย่างถูกต้องถ้าคุณทำแบบเดียวกันกับ df df = pd.DataFrame(dict(C=['X', 'Y'], D=[5., 6.], E=[7, 8], F=['W', 'Z']))มันจะเลื่อน'XY'คอลัมน์ไปทาง'F'คอลัมน์ทั้งหมดนี่เป็นสิ่งที่ผิดสำหรับฉันรุ่นแพนด้าของฉันคือ0.24.2มัน shoudl ทำการdtypeส่งเสริมและไม่เปลี่ยนคอลัมน์ในลักษณะเช่นนี้ a way
EdChum


1

ฉันลองใช้numpyวิธี วิธีการทำงานตราบเท่าที่คุณเก็บข้อมูลของคุณในอาร์เรย์ numpy:

def shift_df(data, n):
    shifted = np.roll(data, n)
    shifted[:, :n] = np.NaN

    return shifted

shifted(df, 1)

array([[nan, 1, 1.0, 'X', 4.0],
       [nan, 2, 2.0, 'Y', 5.0]], dtype=object)

แต่เมื่อคุณเรียกใช้ตัวDataFrameสร้างคอลัมน์ทั้งหมดจะถูกแปลงเป็นobjectแม้ว่าค่าในอาร์เรย์จะเป็นfloat, int, object:

def shift_df(data, n):
    shifted = np.roll(data, n)
    shifted[:, :n] = np.NaN
    shifted = pd.DataFrame(shifted)

    return shifted

print(shift_df(df, 1),'\n')
print(shift_df(df, 1).dtypes)

     0  1  2  3  4
0  NaN  1  1  X  4
1  NaN  2  2  Y  5 

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