Tetapkan jenis dtipe kolom bingkai data panda

111

Saya ingin mengatur dtypes dari beberapa kolom di pd.Dataframe(Saya memiliki file yang harus saya parse secara manual ke dalam daftar daftar, karena file tersebut tidak dapat menerima pd.read_csv)

import pandas as pd
print pd.DataFrame([['a','1'],['b','2']],
                   dtype={'x':'object','y':'int'},
                   columns=['x','y'])

saya mendapat

ValueError: entry not a 2- or 3- tuple

Satu-satunya cara saya dapat mengaturnya adalah dengan mengulang setiap variabel kolom dan menyusunnya kembali astype.

dtypes = {'x':'object','y':'int'}
mydata = pd.DataFrame([['a','1'],['b','2']],
                      columns=['x','y'])
for c in mydata.columns:
    mydata[c] = mydata[c].astype(dtypes[c])
print mydata['y'].dtype   #=> int64

Apakah ada cara yang lebih baik?

hatmatrix
sumber
Ini mungkin permintaan bug / fitur yang bagus , saat ini saya tidak yakin apa yang dilakukan dtype arg (Anda dapat memberikannya skalar, tetapi tidak ketat) ...
Andy Hayden
2
FYI: df = pd.DataFrame([['a','1'],['b','2']], dtype='int', columns=['x','y'])"bekerja" ... tetapi: s
Andy Hayden
1
Ya, memang "berhasil"; tak terduga ...
hatmatrix
Masalah GitHub ini mungkin akan segera menjadi relevan: github.com/pydata/pandas/issues/9287
Amelio Vazquez-Reina

Jawaban:

65

Sejak 0.17, Anda harus menggunakan konversi eksplisit:

pd.to_datetime, pd.to_timedelta and pd.to_numeric

(Seperti yang disebutkan di bawah, tidak ada lagi "sihir", convert_objectstidak digunakan lagi di 0.17)

df = pd.DataFrame({'x': {0: 'a', 1: 'b'}, 'y': {0: '1', 1: '2'}, 'z': {0: '2018-05-01', 1: '2018-05-02'}})

df.dtypes

x    object
y    object
z    object
dtype: object

df

   x  y           z
0  a  1  2018-05-01
1  b  2  2018-05-02

Anda dapat menerapkan ini ke setiap kolom yang ingin Anda konversi:

df["y"] = pd.to_numeric(df["y"])
df["z"] = pd.to_datetime(df["z"])    
df

   x  y          z
0  a  1 2018-05-01
1  b  2 2018-05-02

df.dtypes

x            object
y             int64
z    datetime64[ns]
dtype: object

dan pastikan dtype diperbarui.


JAWABAN LAMA / TIDAK BERLAKU untuk panda 0.12 - 0.16: Anda dapat menggunakan convert_objectsuntuk menyimpulkan tipe yang lebih baik:

In [21]: df
Out[21]: 
   x  y
0  a  1
1  b  2

In [22]: df.dtypes
Out[22]: 
x    object
y    object
dtype: object

In [23]: df.convert_objects(convert_numeric=True)
Out[23]: 
   x  y
0  a  1
1  b  2

In [24]: df.convert_objects(convert_numeric=True).dtypes
Out[24]: 
x    object
y     int64
dtype: object

Sihir! (Sedih melihat itu ditinggalkan.)

Andy Hayden
sumber
2
seperti type.convertdi R sedikit; bagus tetapi meninggalkan orang yang menginginkan spesifikasi eksplisit dalam beberapa kasus.
hatmatrix
1
Hati-hati jika Anda memiliki kolom yang harus berupa string tetapi berisi setidaknya satu nilai yang dapat diubah menjadi int. Yang dibutuhkan hanyalah satu nilai dan seluruh bidang diubah menjadi float64
Michael David Watson
18
Saya perhatikan convert_objects()sudah usang ... saya tidak yakin apa yang menggantikannya?
joefromct
6
Untuk menyimpulkan kembali dtypes data untuk kolom objek, gunakan DataFrame.infer_objects ()
James Tobin
1
@smci oke, saya sudah edit. Ada banyak jawaban yang tidak berlaku lagi, saya perlu mencari cara untuk menemukan semuanya.
Andy Hayden
62

Untuk yang datang dari Google (dll.) Seperti saya:

convert_objects sudah tidak digunakan lagi sejak 0.17 - jika Anda menggunakannya, Anda akan mendapatkan peringatan seperti ini:

FutureWarning: convert_objects is deprecated.  Use the data-type specific converters 
pd.to_datetime, pd.to_timedelta and pd.to_numeric.

Anda harus melakukan sesuatu seperti berikut:

Jack Yates
sumber
Jika Anda memasukkan beberapa contoh, pd.to_datetime, to_timedelta, to_numericini seharusnya jawaban yang diterima.
smci
41

Anda dapat menyetel tipe secara eksplisit dengan panda DataFrame.astype(dtype, copy=True, raise_on_error=True, **kwargs)dan memasukkan kamus dengan dtypes yang Anda inginkandtype

inilah contohnya:

import pandas as pd
wheel_number = 5
car_name = 'jeep'
minutes_spent = 4.5

# set the columns
data_columns = ['wheel_number', 'car_name', 'minutes_spent']

# create an empty dataframe
data_df = pd.DataFrame(columns = data_columns)
df_temp = pd.DataFrame([[wheel_number, car_name, minutes_spent]],columns = data_columns)
data_df = data_df.append(df_temp, ignore_index=True) 

In [11]: data_df.dtypes
Out[11]:
wheel_number     float64
car_name          object
minutes_spent    float64
dtype: object

data_df = data_df.astype(dtype= {"wheel_number":"int64",
        "car_name":"object","minutes_spent":"float64"})

sekarang Anda dapat melihat bahwa itu berubah

In [18]: data_df.dtypes
Out[18]:
wheel_number       int64
car_name          object
minutes_spent    float64
Lauren
sumber
13

Cara lain untuk menyetel tipe kolom adalah dengan membuat larik record numpy dengan tipe yang Anda inginkan, mengisinya, lalu meneruskannya ke konstruktor DataFrame.

import pandas as pd
import numpy as np    

x = np.empty((10,), dtype=[('x', np.uint8), ('y', np.float64)])
df = pd.DataFrame(x)

df.dtypes ->

x      uint8
y    float64
Kaushik Ghose
sumber
0

menghadapi masalah yang sama denganmu. Dalam kasus saya, saya memiliki 1000 file dari log cisco yang perlu saya parse secara manual.

Agar fleksibel dengan bidang dan tipe, saya telah berhasil menguji menggunakan StringIO + read_cvs yang memang menerima dikt untuk spesifikasi dtype.

Saya biasanya mendapatkan setiap file (5k-20k baris) ke dalam buffer dan membuat kamus dtype secara dinamis.

Akhirnya saya menggabungkan (dengan kategoris ... terima kasih kepada 0.19) dataframe ini ke dalam bingkai data besar yang saya buang ke hdf5.

Sesuatu di sepanjang garis ini

import pandas as pd
import io 

output = io.StringIO()
output.write('A,1,20,31\n')
output.write('B,2,21,32\n')
output.write('C,3,22,33\n')
output.write('D,4,23,34\n')

output.seek(0)


df=pd.read_csv(output, header=None,
        names=["A","B","C","D"],
        dtype={"A":"category","B":"float32","C":"int32","D":"float64"},
        sep=","
       )

df.info()

<class 'pandas.core.frame.DataFrame'>
RangeIndex: 5 entries, 0 to 4
Data columns (total 4 columns):
A    5 non-null category
B    5 non-null float32
C    5 non-null int32
D    5 non-null float64
dtypes: category(1), float32(1), float64(1), int32(1)
memory usage: 205.0 bytes
None

Tidak terlalu pythonic .... tetapi melakukan pekerjaan itu

Semoga membantu.

JC

Julian C
sumber
0

Anda lebih baik menggunakan np.arrays yang diketik, lalu meneruskan data dan nama kolom sebagai kamus.

import numpy as np
import pandas as pd
# Feature: np arrays are 1: efficient, 2: can be pre-sized
x = np.array(['a', 'b'], dtype=object)
y = np.array([ 1 ,  2 ], dtype=np.int32)
df = pd.DataFrame({
   'x' : x,    # Feature: column name is near data array
   'y' : y,
   }
 )
Clem Wang
sumber