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


175

아래와 같이 .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

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


3
누락 / NaN 값이 있으면 정수 값을 시리즈 / 데이터 프레임으로 변환하거나 저장할 수 없다고 생각합니다. 이것은 numpy 호환성과 관련이 있다고 생각합니다 (여기서 추측하고 있습니다). 누락 된 값 호환성을 원한다면 값을 float로 저장합니다.
EdChum

1
여기를 참조하십시오 : pandas.pydata.org/pandas-docs/dev/… ; u 값이 누락되었거나 기술적으로 객체 dtype이지만 비효율적 인 경우 float dtype이 있어야합니다. int 유형을 사용하는 목표는 무엇입니까?
Jeff

6
팬더에만 국한되지 않은 NumPy 문제라고 생각합니다. null 값의 가능성을 허용하는 int 유형이 큰 float 열보다 훨씬 더 효율적인 경우가 많기 때문에 부끄러운 일입니다.
ely

1
나도 이것에 문제가 있습니다. 여러 "정수"열의 문자열 표현을 기반으로 병합하려는 여러 데이터 프레임이 있습니다. 그러나 이러한 정수 열 중 하나에 np.nan이 있으면 문자열 캐스팅에서 ".0"을 생성하여 병합을 중단합니다. 일을 약간 더 복잡하게 만들고 간단한 해결 방법이 있으면 좋을 것입니다.
dermen

1
@Rhubarb, 선택적 Nullable Integer Support가 공식적으로 pandas 0.24.0에 추가되었습니다-최종적으로 :)-업데이트 된 답변을 찾으십시오. pandas 0.24.x 출시 노트
mork

답변:


169

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

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


13
수레처럼 처리하는 것 외에 다른 해결 방법이 있습니까?
NumenorForLife

3
@ jsc123에서는 객체 dtype을 사용할 수 있습니다. 이것은 작은 건강 경고와 함께 제공되지만 대부분 잘 작동합니다.
Andy Hayden

1
Object dtype을 사용하는 방법의 예를 제공 할 수 있습니까? 팬더 문서와 인터넷 검색을 살펴 보았으며 권장되는 방법임을 읽었습니다. 그러나 객체 dtype을 사용하는 방법에 대한 예를 찾지 못했습니다.
MikeyE

29
v0.24에서는 이제 df = df.astype(pd.Int32Dtype())(전체 dataFrame을 변환하기 위해) 또는을 수행 할 수 있습니다 df['col'] = df['col'].astype(pd.Int32Dtype()). 허용되는 다른 nullable 정수 유형은 pd.Int16Dtypepd.Int64Dtype입니다. 독을 선택하십시오.
cs95

1
NaN 값이지만 isnan 검사가 전혀 작동하지 않습니다. (
Winston

117

버전 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

열을 널 입력 가능 정수로 변환하려면 다음을 사용하십시오.

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

4
나는이 답변을 좋아한다.
cs95

8
참고 DTYPE은이어야 "Int64"하지 "int64"(첫 번째 'i'를 대문자이어야 함)
비아체슬라프 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는 정수 열을 원합니다. 문자열로 변환하면 조건을 충족하지 않습니다.
Rishab Gupta 1

1
col에 -1이없는 경우에만 작동합니다. 그렇지 않으면 데이터가 엉망이됩니다
Sharvari Gc

그런 다음 int로 돌아 오는 방법 .. ??
abdoulsn

5

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

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


4

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

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

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


3

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

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

3

.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

2

여기서 대부분의 솔루션은 플레이스 홀더 정수를 사용하여 널을 나타내는 방법을 알려줍니다. 정수가 소스 데이터에 표시되지 않을지 확실하지 않은 경우에는이 방법이 도움이되지 않습니다. 내 메소드는 10 진수 값없이 float 형식을 지정하고 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에서 실행되는 코드의 파이썬 프론트 엔드이므로 유형 안전이 필요하며 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

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'))
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.