Saya bekerja dengan baris individual bingkai data panda, tapi saya tersandung masalah paksaan saat mengindeks dan menyisipkan baris. Panda sepertinya selalu ingin memaksa dari int campuran / float ke semua tipe float, dan saya tidak bisa melihat kontrol yang jelas pada perilaku ini.
Sebagai contoh, ini adalah kerangka data sederhana dengan a
as int
dan b
as float
:
import pandas as pd
pd.__version__ # '0.25.2'
df = pd.DataFrame({'a': [1], 'b': [2.2]})
print(df)
# a b
# 0 1 2.2
print(df.dtypes)
# a int64
# b float64
# dtype: object
Berikut ini adalah masalah pemaksaan saat mengindeks satu baris:
print(df.loc[0])
# a 1.0
# b 2.2
# Name: 0, dtype: float64
print(dict(df.loc[0]))
# {'a': 1.0, 'b': 2.2}
Dan ini adalah masalah pemaksaan saat memasukkan satu baris:
df.loc[1] = {'a': 5, 'b': 4.4}
print(df)
# a b
# 0 1.0 2.2
# 1 5.0 4.4
print(df.dtypes)
# a float64
# b float64
# dtype: object
Dalam kedua contoh, saya ingin a
kolom tetap sebagai tipe integer, daripada dipaksa ke tipe float.
df.loc[[0], df.columns]
.read_[type]
mendukung beberapa dtypes ...Jawaban:
Setelah beberapa penggalian, berikut adalah beberapa solusi yang sangat jelek. (Jawaban yang lebih baik akan diterima.)
Sebuah kekhasan yang ditemukan di sini adalah bahwa kolom non-numerik menghentikan paksaan, jadi inilah cara mengindeks satu baris ke
dict
:Dan memasukkan baris dapat dilakukan dengan membuat bingkai data baru dengan satu baris:
Kedua trik ini tidak dioptimalkan untuk bingkai data yang besar, jadi saya akan sangat menghargai jawaban yang lebih baik!
sumber
df['a'] = df.a.astype(mytype)
... Ini masih kotor dan mungkin tidak efisien..astype()
berbahaya untuk float -> integer; tidak ada masalah berubah1.1
menjadi1
, jadi Anda benar-benar harus memastikan semua nilai Anda 'seperti integer' sebelum melakukannya. Mungkin yang terbaik untuk digunakanpd.to_numeric
dengandowncast='integer'
Akar masalahnya adalah itu
Kita dapat melihat bahwa:
Dan seri hanya dapat memiliki satu jenis, dalam kasus Anda baik int64 atau float64.
Ada dua solusi yang muncul di kepala saya:
atau
https://github.com/pandas-dev/pandas/blob/master/pandas/core/frame.py#L6973
Jadi langkah Anda sebenarnya adalah langkah yang solid, atau kita bisa:
sumber
object
tipe data! Satu lagi adalah membuat objek DataFrame dari awal:df = pd.DataFrame({'a': [1], 'b': [2.2]}, dtype=object)
Setiap kali Anda mendapatkan data dari kerangka data atau menambahkan data ke kerangka data dan perlu menjaga tipe data tetap sama, hindari konversi ke struktur internal lain yang tidak mengetahui tipe data yang dibutuhkan.
Ketika Anda melakukan
df.loc[0]
itu mengkonversi kepd.Series
,Dan sekarang,
Series
hanya akan memiliki satudtype
. Dengan demikian memaksaint
untukfloat
.Alih-alih menjaga struktur sebagai
pd.DataFrame
,Pilih baris yang diperlukan sebagai bingkai dan kemudian konversikan ke
dict
Demikian pula, untuk menambahkan baris baru, Gunakan
pd.DataFrame.append
fungsi panda ,Di atas tidak akan menyebabkan konversi jenis,
sumber
Pendekatan berbeda dengan sedikit manipulasi data:
Asumsikan Anda memiliki daftar kamus (atau bingkai data)
lod=[{'a': [1], 'b': [2.2]}, {'a': [5], 'b': [4.4]}]
di mana setiap kamus mewakili satu baris (perhatikan daftar dalam kamus kedua). Kemudian Anda dapat membuat kerangka data dengan mudah melalui:
dan Anda mempertahankan jenis kolom. Lihat konser
Jadi jika Anda memiliki kerangka data dan daftar dicts, Anda bisa menggunakannya
sumber
Dalam kasus pertama, Anda bisa bekerja dengan tipe data integer nullable . Pilihan Seri tidak memaksa
float
dan nilai ditempatkan dalamobject
wadah. Kamus kemudian dibuat dengan benar, dengan nilai dasar disimpan sebagai anp.int64
.Dengan sintaks Anda, ini hampir berfungsi untuk kasus kedua juga, tetapi ini tidak benar
object
, jadi tidak bagus:Namun, kita dapat membuat perubahan kecil pada sintaks untuk menambahkan baris di akhir (dengan RangeIndex) dan sekarang jenis ditangani dengan benar.
sumber