IT story

NaN이 포함 된 Pandas 열을 dtype`int`로 변환

hot-time 2020. 7. 5. 07:58
반응형

NaN이 포함 된 Pandas 열을 dtype`int`로 변환


이 질문에는 이미 답변이 있습니다.

아래와 같이 .csv 파일에서 Pandas 데이터 프레임으로 데이터를 읽습니다. 열 중 하나, 즉 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

이 문제를 어떻게 해결할 수 있습니까?


정수 열에 NaN rep가없는 것은 팬더 "gotcha" 입니다.

일반적인 해결 방법은 플로트를 사용하는 것입니다.


버전 0.24. +에서 팬더는 결 측값이있는 정수 dtype을 보유하는 기능을 얻었습니다.

널 입력 가능 정수 데이터 유형 .

팬더는을 사용하여 값이 누락 된 정수 데이터를 나타낼 수 있습니다 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

내 유스 케이스는 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을 다시 삽입하십시오.

예쁘지는 않지만 작업이 완료됩니다!


저장된 데이터를 수정할 수있는 경우 센티넬 값을 사용하여 missing을 찾으십시오 id. 열 이름으로 유추되는 일반적인 유스 케이스 id는 엄격하게 0보다 큰 정수 0이므로 센티넬 값으로 사용 하여 쓸 수 있습니다.

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

.dropna()NaN 값으로 행을 삭제해도 괜찮다면 사용할 수 있습니다 .

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)

예를 들어, float가 정밀도를 잃을 수있는 방법의 예는 다음과 같습니다.

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

그리고 출력은 다음과 같습니다

1.2345678901234567e+19 12345678901234567168 12345678901234567890

열에서 정수와 NaN을 절대적으로 결합하려면 'object'데이터 유형을 사용할 수 있습니다.

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

이것은 NaN을 정수로 바꾸고 (어떤 것이 중요하지는 않지만) int로 변환하고 객체로 변환 한 다음 NaN을 다시 삽입합니다.


이제 NaN을 dtype으로 포함하는 팬더 열을 만들 수 있습니다. 이는 팬더 0.24.0 int에 공식적으로 추가 되었기 때문입니다.

pandas 0.24.x 출시 노트 인용문 : " Pandas는 값이없는 정수 dtype을 보유 할 수있는 기능을 얻었습니다.


I ran into this issue working with pyspark. As this is a python frontend for code running on a jvm, it requires type safety and using float instead of int is not an option. I worked around the issue by wrapping the pandas pd.read_csv in a function that will fill user-defined columns with user-defined fill values before casting them to the required type. Here is what I ended up using:

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

First remove the rows which contain NaN. Then do Integer conversion on remaining rows. At Last insert the removed rows again. Hope it will work


Most solutions here tell you how to use a placeholder integer to represent nulls. That approach isn't helpful if you're uncertain that integer won't show up in your source data though. My method with will format floats without their decimal values and convert nulls to None's. The result is an object datatype that will look like an integer field with null values when loaded into a CSV.

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

Assuming your DateColumn formatted 3312018.0 should be converted to 03/31/2018 as a string. And, some records are missing or 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'))

참고URL : https://stackoverflow.com/questions/21287624/convert-pandas-column-containing-nans-to-dtype-int

반응형