リストのリストとして表されているテーブルをPandas DataFrameに変換したいのですが。非常に単純化された例として:
a = [['a', '1.2', '4.2'], ['b', '70', '0.03'], ['x', '5', '0']]
df = pd.DataFrame(a)
列を適切な型、この場合は列2と3にfloat型に変換するための最善の方法は何ですか? DataFrameへの変換中に型を指定する方法はありますか?それとも、最初にDataFrameを作成し、次に列をループ処理して各列の型を変更する方が良いでしょうか。何百もの列がある可能性があり、どの列がどの型であるかを正確に指定したくないので、理想的には動的にこれを実行したいと思います。保証できるのは、各列に同じ型の値が含まれていることだけです。
パンダの型を変換するための3つの主なオプションがあります。
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
ご覧のとおり、新しいシリーズが返されます。この出力を変数名または列名に割り当てて使用し続けることを忘れないでください。
# convert Series
my_series = pd.to_numeric(my_series)
# convert column "a" of a DataFrame
df["a"] = pd.to_numeric(df["a"])
apply()
メソッドを使ってDataFrameの複数の列を変換するのにも使えます。
# 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
にすることや、これらの値を含む列を無視することができます。
これは、オブジェクトdtypeを持つ一連の文字列s
を使った例です。
>>> 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
失敗するのではなく、「パンダ」を欠けているか悪い数値と見なしたいと思うかもしれません。 NaN
キーワード引数を使用して、次のように無効な値をerrors
に強制変換できます。
>>> pd.to_numeric(s, errors='coerce')
0 1.0
1 2.0
2 4.7
3 NaN
4 10.0
dtype: float64
errors
の3番目のオプションは、無効な値が見つかった場合に操作を無視することです。
>>> pd.to_numeric(s, errors='ignore')
# the original Series is returned untouched
この最後のオプションは、DataFrame全体を変換したいが、どの列を確実に数値型に変換できるのかわからない場合に特に便利です。その場合は、単に書いてください:
df.apply(pd.to_numeric, errors='ignore')
関数はDataFrameの各列に適用されます。数値型に変換できる列は変換されますが、できない列(たとえば、数字以外の文字列や日付を含む列)はそのままになります。
デフォルトでは、to_numeric()
を使った変換はint64
かfloat64
dtype(あるいはあなたのプラットフォームに固有のどんな整数幅でも)のどちらかをあなたに与えるでしょう。
それは通常あなたが望むものですが、もしあなたがいくらかのメモリを節約しそしてfloat32
またはint8
のようなもっとコンパクトなdtypeを使いたいとしたらどうしますか?
to_numeric()
は 'integer'、 'signed'、 'unsigned'、 'float'のいずれかにダウンキャストするオプションを与えます。整数型の単純な系列s
の例を示します。
>>> s = pd.Series([1, 2, -7])
>>> s
0 1
1 2
2 -7
dtype: int64
'integer'へのダウンキャストは、値を保持できる最小の整数を使用します。
>>> pd.to_numeric(s, downcast='integer')
0 1
1 2
2 -7
dtype: int8
同様に 'float'にダウンキャストすると、通常の浮動小数点型よりも小さい型が選択されます。
>>> pd.to_numeric(s, downcast='float')
0 1.0
1 2.0
2 -7.0
dtype: float32
astype()
astype()
メソッドを使用すると、DataFrameまたはSeriesに持たせるdtypeについて明示的に指定できます。あるタイプから別のタイプに試すことができるという点で非常に用途が広いです。
型を選ぶだけです。NumPy型(例:np.int16
)、一部のPython型(例:bool)、またはパンダ固有の型(カテゴリ型dtypeなど)を使用できます。
変換したいオブジェクトのメソッドを呼び出すと、astype()
がそれを試して変換します。
# 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')
astype()
がSeriesまたはDataFrame内の値を変換する方法を知らない場合、エラーが発生します。例えばNaN
またはinf
の値がある場合、それを整数に変換しようとするとエラーが発生します。
パンダ0.20.0の時点で、このエラーはerrors='ignore'
を渡すことによって抑制することができます。元のオブジェクトはそのまま残ります。
astype()
は強力ですが、値を「誤って」変換することがあります。例えば:
>>> s = pd.Series([1, 2, -7])
>>> s
0 1
1 2
2 -7
dtype: int64
これらは小さい整数なので、メモリを節約するために符号なし8ビット型に変換してはどうでしょうか。
>>> s.astype(np.uint8)
0 1
1 2
2 249
dtype: uint8
変換はうまくいったが、-7は249になるように丸められた(すなわち28 - 7)!
代わりにpd.to_numeric(s, downcast='unsigned')
を使ってダウンキャストしようとすると、このエラーを防ぐことができます。
infer_objects()
パンダのバージョン0.21.0では、オブジェクトデータ型を持つDataFrameのカラムをより具体的なタイプに変換する(ソフト変換)ためのメソッド infer_objects()
が導入されました。
たとえば、これは2列のオブジェクト型を持つDataFrameです。一方は実際の整数を保持し、もう一方は整数を表す文字列を保持します。
>>> df = pd.DataFrame({'a': [7, 1, 5], 'b': ['3','2','1']}, dtype='object')
>>> df.dtypes
a object
b object
dtype: object
infer_objects()
を使うと、カラム 'a'の型をint64に変えることができます。
>>> df = df.infer_objects()
>>> df.dtypes
a int64
b object
dtype: object
値が整数ではなく文字列であるため、列 'b'はそのまま残されています。両方の列を整数型に変換しようとする場合は、代わりにdf.astype(int)
を使用できます。
これはどう?
a = [['a', '1.2', '4.2'], ['b', '70', '0.03'], ['x', '5', '0']]
df = pd.DataFrame(a, columns=['one', 'two', 'three'])
df
Out[16]:
one two three
0 a 1.2 4.2
1 b 70 0.03
2 x 5 0
df.dtypes
Out[17]:
one object
two object
three object
df[['two', 'three']] = df[['two', 'three']].astype(float)
df.dtypes
Out[19]:
one object
two float64
three float64
この下のコードは列のデータ型を変更します。
df[['col.name1', 'col.name2'...]] = df[['col.name1', 'col.name2'..]].astype('data_type')
データ型の代わりにあなたのデータ型を与えることができます。str、float、intなどが好きですか。
これは、引数としてDataFrameと列のリストを受け取り、列内のすべてのデータを数値に変換する関数です。
# df is the DataFrame, and column_list is a list of columns as strings (e.g ["col1","col2","col3"])
# dependencies: pandas
def coerce_df_columns_to_numeric(df, column_list):
df[column_list] = df[column_list].apply(pd.to_numeric, errors='coerce')
だから、あなたの例では:
import pandas as pd
def coerce_df_columns_to_numeric(df, column_list):
df[column_list] = df[column_list].apply(pd.to_numeric, errors='coerce')
a = [['a', '1.2', '4.2'], ['b', '70', '0.03'], ['x', '5', '0']]
df = pd.DataFrame(a, columns=['col1','col2','col3'])
coerce_df_columns_to_numeric(df, ['col2','col3'])
それぞれの列に異なるデータ型を持つ2つのデータフレームを作成し、それらを一緒に追加するのはどうですか。
d1 = pd.DataFrame(columns=[ 'float_column' ], dtype=float)
d1 = d1.append(pd.DataFrame(columns=[ 'string_column' ], dtype=str))
結果
In[8}: d1.dtypes
Out[8]:
float_column float64
string_column object
dtype: object
データフレームを作成したら、1列目に浮動小数点変数を、2列目に文字列(または任意のデータ型)を入力できます。
特定の列を指定するだけで、明示的にしたい場合は、( DOCS LOCATION あたり)
dataframe = dataframe.astype({'col_name_1':'int','col_name_2':'float64', etc. ...})
そのため、元の質問を使用しますが、列名を指定します。
a = [['a', '1.2', '4.2'], ['b', '70', '0.03'], ['x', '5', '0']]
df = pd.DataFrame(a, columns=['col_name_1', 'col_name_2', 'col_name_3'])
df = df.astype({'col_name_2':'float64', 'col_name_3':'float64'})
私は同じ問題を抱えていると思いましたが、実際には問題が解決しやすいようにわずかな違いがあります。この質問を見ている他の人にとっては、あなたの入力リストのフォーマットをチェックする価値があります。私の場合は、最初の質問のように数字は文字列ではなくフロートです。
a = [['a', 1.2, 4.2], ['b', 70, 0.03], ['x', 5, 0]]
しかし、データフレームを作成する前にリストを処理しすぎると、型が失われ、すべてが文字列になります。
テンキー配列を介したデータフレームの作成
df = pd.DataFrame(np.array(a))
df
Out[5]:
0 1 2
0 a 1.2 4.2
1 b 70 0.03
2 x 5 0
df[1].dtype
Out[7]: dtype('O')
質問の場合と同じデータフレームを指定します。列1と2のエントリは文字列と見なされます。しかしやって
df = pd.DataFrame(a)
df
Out[10]:
0 1 2
0 a 1.2 4.20
1 b 70.0 0.03
2 x 5.0 0.00
df[1].dtype
Out[11]: dtype('float64')
実際には正しいフォーマットの列を持つデータフレームを与える