pandasの列タイプを変更する 質問する

pandasの列タイプを変更する 質問する

リストのリストから DataFrame を作成しました:

table = [
    ['a',  '1.2',  '4.2' ],
    ['b',  '70',   '0.03'],
    ['x',  '5',    '0'   ],
]

df = pd.DataFrame(table)

列を特定の型に変換するにはどうすればよいですか? この場合、列 2 と 3 を float に変換します。

リストを DataFrame に変換するときに型を指定する方法はありますか? それとも、最初に DataFrame を作成し、次に列をループして各列の dtype を変更する方がよいでしょうか? 列は数百ある可能性があり、どの列がどの型であるかを正確に指定したくはないので、理想的にはこれを動的な方法で行いたいです。私が保証できるのは、各列に同じ型の値が含まれているということだけです。

ベストアンサー1

pandas で型を変換するには、主に 4 つのオプションがあります。

  1. to_numeric()- 非数値型(文字列など)を適切な数値型に安全に変換する機能を提供します。(参照:to_datetime()そしてto_timedelta()

  2. astype()- (ほぼ)あらゆる型を(ほぼ)あらゆる他の型に変換します(そうすることが必ずしも賢明ではない場合でも)。また、カテゴリータイプ(非常に便利です)。

  3. infer_objects()- 可能であれば、Python オブジェクトを保持するオブジェクト列を pandas 型に変換するユーティリティ メソッド。

  4. convert_dtypes()- DataFrame 列を、サポートされる「可能な限り最良の」dtype pd.NA(欠損値を示す pandas オブジェクト) に変換します。

それぞれの方法の詳細な説明と使用方法については、以下をお読みください。


1.to_numeric()

DataFrameの1つ以上の列を数値に変換する最良の方法は、pandas.to_numeric()

この関数は、非数値オブジェクト (文字列など) を必要に応じて整数または浮動小数点数に変換しようとします。

基本的な使い方

入力to_numeric()Series または DataFrame の単一の列です。

>>> s = pd.Series(["8", 6, "7.5", 3, "0.9"]) # mixed string and numeric values
>>> s
0      8
1      6
2    7.5
3      3
4    0.9
dtype: object

>>> pd.to_numeric(s) # convert everything to float values
0    8.0
1    6.0
2    7.5
3    3.0
4    0.9
dtype: float64

ご覧のとおり、新しい Series が返されます。引き続き使用するには、この出力を変数または列名に割り当てることを忘れないでください。

# convert Series
my_series = pd.to_numeric(my_series)

# convert column "a" of a DataFrame
df["a"] = pd.to_numeric(df["a"])

また、これを使用して、DataFrameの複数の列を変換することもできます。apply()方法:

# convert all columns of DataFrame
df = df.apply(pd.to_numeric) # convert all columns of DataFrame

# convert just columns "a" and "b"
df[["a", "b"]] = df[["a", "b"]].apply(pd.to_numeric)

すべての値を変換できる限り、おそらくそれだけで十分でしょう。

エラー処理

しかし、一部の値を数値型に変換できない場合はどうなるでしょうか?

to_numeric()また、errors非数値を に強制したりNaN、これらの値を含む列を単に無視したりできるキーワード引数も受け取ります。

s以下は、オブジェクト dtype を持つ文字列のシリーズを使用する例です。

>>> s = pd.Series(['1', '2', '4.7', 'pandas', '10'])
>>> s
0         1
1         2
2       4.7
3    pandas
4        10
dtype: object

デフォルトの動作では、値を変換できない場合に例外が発生します。この場合、文字列 'pandas' を処理できません。

>>> pd.to_numeric(s) # or pd.to_numeric(s, errors='raise')
ValueError: Unable to parse string

失敗するのではなく、「pandas」を欠落した/不正な数値と見なすようにしたい場合があります。キーワード引数NaNを使用して、無効な値を次のように強制できます。errors

>>> pd.to_numeric(s, errors='coerce')
0     1.0
1     2.0
2     4.7
3     NaN
4    10.0
dtype: float64

3 番目のオプションは、errors無効な値に遭遇した場合に操作を無視することです。

>>> pd.to_numeric(s, errors='ignore')
# the original Series is returned untouched

この最後のオプションは、DataFrame 全体を変換する場合に特に便利ですが、どの列が確実に数値型に変換できるかわからない場合です。その場合は、次のように記述します。

df.apply(pd.to_numeric, errors='ignore')

The function will be applied to each column of the DataFrame. Columns that can be converted to a numeric type will be converted, while columns that cannot (e.g. they contain non-digit strings or dates) will be left alone.

Downcasting

By default, conversion with to_numeric() will give you either an int64 or float64 dtype (or whatever integer width is native to your platform).

That's usually what you want, but what if you wanted to save some memory and use a more compact dtype, like float32, or int8?

to_numeric() gives you the option to downcast to either 'integer', 'signed', 'unsigned', 'float'. Here's an example for a simple series s of integer type:

>>> s = pd.Series([1, 2, -7])
>>> s
0    1
1    2
2   -7
dtype: int64

Downcasting to 'integer' uses the smallest possible integer that can hold the values:

>>> pd.to_numeric(s, downcast='integer')
0    1
1    2
2   -7
dtype: int8

Downcasting to 'float' similarly picks a smaller than normal floating type:

>>> pd.to_numeric(s, downcast='float')
0    1.0
1    2.0
2   -7.0
dtype: float32

2. astype()

The astype() method enables you to be explicit about the dtype you want your DataFrame or Series to have. It's very versatile in that you can try and go from one type to any other.

Basic usage

Just pick a type: you can use a NumPy dtype (e.g. np.int16), some Python types (e.g. bool), or pandas-specific types (like the categorical dtype).

Call the method on the object you want to convert and astype() will try and convert it for you:

# convert all DataFrame columns to the int64 dtype
df = df.astype(int)

# convert column "a" to int64 dtype and "b" to complex type
df = df.astype({"a": int, "b": complex})

# convert Series to float16 type
s = s.astype(np.float16)

# convert Series to Python strings
s = s.astype(str)

# convert Series to categorical type - see docs for more details
s = s.astype('category')

Notice I said "try" - if astype() does not know how to convert a value in the Series or DataFrame, it will raise an error. For example, if you have a NaN or inf value you'll get an error trying to convert it to an integer.

As of pandas 0.20.0, this error can be suppressed by passing errors='ignore'. Your original object will be returned untouched.

Be careful

astype() is powerful, but it will sometimes convert values "incorrectly". For example:

>>> s = pd.Series([1, 2, -7])
>>> s
0    1
1    2
2   -7
dtype: int64

These are small integers, so how about converting to an unsigned 8-bit type to save memory?

>>> s.astype(np.uint8)
0      1
1      2
2    249
dtype: uint8

The conversion worked, but the -7 was wrapped round to become 249 (i.e. 28 - 7)!

Trying to downcast using pd.to_numeric(s, downcast='unsigned') instead could help prevent this error.


3. infer_objects()

Version 0.21.0 of pandas introduced the method infer_objects() for converting columns of a DataFrame that have an object datatype to a more specific type (soft conversions).

For example, here's a DataFrame with two columns of object type. One holds actual integers and the other holds strings representing integers:

>>> df = pd.DataFrame({'a': [7, 1, 5], 'b': ['3','2','1']}, dtype='object')
>>> df.dtypes
a    object
b    object
dtype: object

Using infer_objects(), you can change the type of column 'a' to int64:

>>> df = df.infer_objects()
>>> df.dtypes
a     int64
b    object
dtype: object

Column 'b' has been left alone since its values were strings, not integers. If you wanted to force both columns to an integer type, you could use df.astype(int) instead.


4. convert_dtypes()

Version 1.0 and above includes a method convert_dtypes() to convert Series and DataFrame columns to the best possible dtype that supports the pd.NA missing value.

ここで「最善」とは、値を保持するのに最も適した型を意味します。たとえば、これは pandas 整数型で、すべての値が整数 (または欠損値) の場合、Python 整数オブジェクトのオブジェクト列は に変換されInt64、NumPy 値の列int32は pandas dtype になりますInt32

objectDataFrame を使用するとdf、次の結果が得られます。

>>> df.convert_dtypes().dtypes                                             
a     Int64
b    string
dtype: object

列 'a' には整数値が格納されていたため、 型に変換されましたInt64( とは異なり、欠損値を保持できますint64)。

列 'b' には文字列オブジェクトが含まれていたため、pandas のstringdtype に変更されました。

デフォルトでは、このメソッドは各列のオブジェクト値から型を推測します。以下を渡すことでこれを変更できますinfer_objects=False:

>>> df.convert_dtypes(infer_objects=False).dtypes                          
a    object
b    string
dtype: object

これで列「a」はオブジェクト列のままになりました。パンダはこれを「整数」列として記述できることを認識しています(内部的にはinfer_dtype) ですが、整数の dtype が正確に何であるか推測しなかったため、変換されませんでした。列 'b' は 'string' 値を保持していると認識されたため、再び 'string' dtype に変換されました。

おすすめ記事