web-dev-qa-db-ja.com

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

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

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

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

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

109
Zhubarb

整数列にNaN担当者がいないのは pandas "gotcha" です。

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

121
Andy Hayden

私のユースケースは、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を再挿入します。

それはきれいではありませんが、仕事を終わらせます!

24
hibernado

バージョン0.24。+では、pandasに、欠損値を持つ整数dtypeを保持する機能が追加されました。

Nullable Integer Data Type

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

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

0      1
1      2
2    NaN
dtype: Int64
16
jezrael

保存されたデータを変更できる場合は、欠落しているidにセンチネル値を使用します。 idが厳密にゼロより大きい整数であるという、列名によって推測される一般的な使用例では、0を番兵値として使用して、

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

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

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

2
mork

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

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

または、.fillna().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
elomage

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

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

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

1
jmenglund

ここでのほとんどのソリューションは、プレースホルダー整数を使用してヌルを表す方法を示しています。ただし、整数がソースデータに表示されないことが確実でない場合、この方法は役に立ちません。を使用する私のメソッドは、小数値を持たない浮動小数点をフォーマットし、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)))
0
Corbin

私はpysparkでこの問題に遭遇しました。これはjvm上で実行されるコードのpythonフロントエンドであるため、タイプセーフが必要であり、intの代わりにfloatを使用することはオプションではありません。 pandas 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
0
Neuneck

3312018.0でフォーマットされたDateColumnを文字列として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'))
0

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

0
kamran kausar