NaNを含むPandas列をdtype `int`に変換します


175

以下のように、.csvファイルからPandasデータフレームにデータを読み取ります。列の1つ、つまりについてid、列のタイプをとして指定しますint。問題は、idシリーズに欠損値/空の値があることです。

id.csvの読み取り中に列を整数にキャストしようとすると、次のようになります。

df= pd.read_csv("data.csv", dtype={'id': int}) 
error: Integer column has NA values

または、以下のように読んだ後、列タイプを変換しようとしましたが、今回は次のようになります:

df= pd.read_csv("data.csv") 
df[['id']] = df[['id']].astype(int)
error: Cannot convert NA to integer

どうすればこれに取り組むことができますか?


3
欠損値/ NaN値がある場合、整数値はシリーズ/データフレームに変換または保存できないと思います。これは、numpyの互換性と関係があると思います(ここでは推測しています)。欠損値の互換性が必要な場合は、値を浮動小数点数として保存します
EdChum

1
ここを参照してください:pandas.pydata.org/pandas-docs/dev/… ; uに欠損値がある場合は、浮動小数点型のdtypeが必要です(または技術的にはオブジェクト型のdtypeですが、これは非効率的です)。int型を使用する目的は何ですか?
Jeff

6
これはNumPyの問題であり、パンダに固有の問題ではないと私は思います。null値の可能性を許容するint型を持っているとフロートの大きな列よりもはるかに効率的である場合が多いので、それは残念です。
2014年

1
これにも問題があります。複数の「整数」列の文字列表現に基づいてマージしたい複数のデータフレームがあります。ただし、これらの整数列の1つにnp.nanがある場合、文字列のキャストによって「.0」が生成され、マージが破棄されます。物事を少し複雑にするだけで、簡単な回避策があればいいでしょう。
dermen 2015

1
@Rhubarb、オプションのNullable Integerサポートがパンダ0.24.0に正式に追加されました-最後に:)-以下の更新された回答を見つけてください。パンダ0.24.xリリースノート
モルク

回答:


169

整数列にNaN repがないことは、パンダの「ごちゃごちゃ」です。

通常の回避策は、単純にフロートを使用することです。


13
フロートのように処理する以外に回避策はありますか?
NumenorForLife 2015年

3
@ jsc123オブジェクトdtypeを使用できます。これには小さなヘルス警告が付属していますが、ほとんどの場合、問題なく機能します。
アンディヘイデン

1
オブジェクトdtypeの使用例を提供できますか?私はパンダのドキュメントとグーグルを調べてきましたが、それが推奨される方法であることを読みました。しかし、私はオブジェクトdtypeの使用例を見つけていません。
MikeyE

28
v0.24では、df = df.astype(pd.Int32Dtype())(dataFrame全体を変換するために)実行できるようになりましたdf['col'] = df['col'].astype(pd.Int32Dtype())。その他の受け入れ可能なnull許容整数型はpd.Int16Dtypeおよびpd.Int64Dtypeです。毒を選びなさい。
cs95

1
NaN値ですが、isnanチェックはまったく機能しません:(
Winston

116

バージョン0.24。+では、pandasは欠損値を持つ整数dtypeを保持する機能を獲得しました。

Nullable Integer Data Type

パンダは、を使用して、欠損値のある可能性のある整数データを表すことができますarrays.IntegerArray。これはパンダ内に実装された拡張タイプです。これは整数のデフォルトのdtypeではなく、推論されません。array()またはに明示的にdtypeを渡す必要がありますSeries

arr = pd.array([1, 2, np.nan], dtype=pd.Int64Dtype())
pd.Series(arr)

0      1
1      2
2    NaN
dtype: Int64

列をnull許容整数に変換するには、以下を使用します。

df['myCol'] = df['myCol'].astype('Int64')

4
私はこの答えが好きです。
cs95

7
dtypeは必須で"Int64"はない"int64"(最初の 'i'は大文字にする必要がある)
Viacheslav Z

2
df.myCol = df.myCol.astype('Int64')またはdf['myCol'] = df['myCol'].astype('Int64')
LoMaPh

43

私のユースケースは、DBテーブルにロードする前にデータを変更することです。

df[col] = df[col].fillna(-1)
df[col] = df[col].astype(int)
df[col] = df[col].astype(str)
df[col] = df[col].replace('-1', np.nan)

NaNを削除し、intに変換し、strに変換してから、NANを再挿入します。

それはきれいではありませんが、それは仕事を成し遂げます!


1
一部がnullで残りがfloatであるシリアル番号を読み込もうとして、髪を抜いてきました。これで助かりました。
Chris Decker

1
OPには整数の列が必要です。文字列に変換することは条件を満たしていません。
リシャブグプタ

1
colにまだ-1がない場合にのみ機能します。そうしないと、データが
乱れ

その後、int .. ??に戻る方法
abdoulsn

5

intパンダ0.24.0に正式に追加されたため、NaNをdtypeとして含むパンダ列を作成できるようになりました。

pandas 0.24.xリリースノート 引用: " Pandasは欠損値のある整数dtypeを保持する機能を獲得しました


4

整数とNaNを列で組み合わせたい場合は、「オブジェクト」データ型を使用できます。

df['col'] = (
    df['col'].fillna(0)
    .astype(int)
    .astype(object)
    .where(df['col'].notnull())
)

これはNaNを整数に置き換え(どちらでもかまいません)、intに変換し、オブジェクトに変換して、最後にNaNを再挿入します。


3

保存したデータを変更できる場合は、行方不明のセンチネル値を使用しますid。列名から推測される一般的なユースケースidは、厳密にゼロより大きい整数であり0、センチネル値として使用できるため、次のように記述できます。

if row['id']:
   regular_process(row)
else:
   special_process(row)

3

.dropna()NaN値を含む行を削除してもよい場合に使用できます。

df = df.dropna(subset=['id'])

または、.fillna()and .astype()を使用してNaNを値に置き換え、それらをintに変換します。

大きな整数でCSVファイルを処理しているときにこの問題に遭遇しましたが、それらの一部が欠落していました(NaN)。精度を失う可能性があるため、型としてfloatを使用することはできませんでした。

私の解決策は、中間型としてstr使用することでした。その後、コードの後半で自由に文字列をintに変換できます。NaNを0に置き換えましたが、任意の値を選択できます。

df = pd.read_csv(filename, dtype={'id':str})
df["id"] = df["id"].fillna("0").astype(int)

説明のために、フロートが精度を失う可能性がある例を次に示します。

s = "12345678901234567890"
f = float(s)
i = int(f)
i2 = int(s)
print (f, i, i2)

そして出力は:

1.2345678901234567e+19 12345678901234567168 12345678901234567890

2

ここでのほとんどのソリューションは、プレースホルダー整数を使用してnullを表す方法を示しています。ただし、整数がソースデータに表示されないことが確実でない場合は、この方法は役に立ちません。私のメソッドは、10進数値なしで浮動小数点数をフォーマットし、nullをNoneに変換します。結果は、CSVに読み込まれたときにnull値を持つ整数フィールドのように見えるオブジェクトデータ型です。

keep_df[col] = keep_df[col].apply(lambda x: None if pandas.isnull(x) else '{0:.0f}'.format(pandas.to_numeric(x)))

1

私はpysparkでこの問題に遭遇しました。これは、jvmで実行されるコードのpythonフロントエンドであるため、タイプセーフが必要であり、intの代わりにfloatを使用することはできません。私はpd.read_csv、必要な型にキャストする前に、ユーザー定義の列をユーザー定義の埋め込み値で埋める関数でパンダをラップすることで問題を回避しました。これが私が最終的に使用したものです:

def custom_read_csv(file_path, custom_dtype = None, fill_values = None, **kwargs):
    if custom_dtype is None:
        return pd.read_csv(file_path, **kwargs)
    else:
        assert 'dtype' not in kwargs.keys()
        df = pd.read_csv(file_path, dtype = {}, **kwargs)
        for col, typ in custom_dtype.items():
            if fill_values is None or col not in fill_values.keys():
                fill_val = -1
            else:
                fill_val = fill_values[col]
            df[col] = df[col].fillna(fill_val).astype(typ)
    return df

1
import pandas as pd

df= pd.read_csv("data.csv")
df['id'] = pd.to_numeric(df['id'])

4
受け入れられた回答で提案されたものよりもこの公式を好む理由はありますか?もしそうなら、その説明を提供するためにあなたの答えを編集することは有用です-特に注目を集めるために競合している10の追加の答えがあるので。
Jeremy Caney

このコードはOPの問題を解決する可能性がありますが、コードがそれに対処する方法/理由に関する説明を含めるのが最善です。このようにして、将来の訪問者はあなたの投稿から学び、それを自分のコードに適用することができます。SOはコーディングサービスではなく、知識のリソースです。また、質の高い、完全な回答が支持される可能性が高くなります。これらの機能は、すべての投稿が自己完結型であるという要件とともに、プラットフォームがフォーラムと区別するSOの強みの一部です。次のことができedit、追加の情報を追加するには&/またはソースのドキュメントを使用して説明を補足します。
SherylHohman

0

まず、NaNを含む行を削除します。次に、残りの行で整数変換を行います。最後に、削除した行をもう一度挿入します。それがうまくいくことを願っています


-1

DateColumn形式の3312018.0を文字列として03/31/2018に変換する必要があると仮定します。また、一部のレコードが欠落しているか、0です。

df['DateColumn'] = df['DateColumn'].astype(int)
df['DateColumn'] = df['DateColumn'].astype(str)
df['DateColumn'] = df['DateColumn'].apply(lambda x: x.zfill(8))
df.loc[df['DateColumn'] == '00000000','DateColumn'] = '01011980'
df['DateColumn'] = pd.to_datetime(df['DateColumn'], format="%m%d%Y")
df['DateColumn'] = df['DateColumn'].apply(lambda x: x.strftime('%m/%d/%Y'))
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.