행을 인덱싱하고 삽입하는 동안 팬더 데이터 프레임의 강제 방지


16

팬더 데이터 프레임의 개별 행을 사용하고 있지만 행을 인덱싱하고 삽입하는 동안 강제 문제로 인해 어려움을 겪고 있습니다. 팬더는 항상 혼합 int / float에서 all-float 유형으로 강제 변환하려고하는 것처럼 보이며이 동작에 대한 명확한 제어 기능을 볼 수 없습니다.

예를 들어 다음은 aas intbas를 사용하는 간단한 데이터 프레임입니다 float.

import pandas as pd
pd.__version__  # '0.25.2'

df = pd.DataFrame({'a': [1], 'b': [2.2]})
print(df)
#    a    b
# 0  1  2.2
print(df.dtypes)
# a      int64
# b    float64
# dtype: object

하나의 행을 인덱싱하는 동안 강제 문제가 있습니다.

print(df.loc[0])
# a    1.0
# b    2.2
# Name: 0, dtype: float64
print(dict(df.loc[0]))
# {'a': 1.0, 'b': 2.2}

그리고 하나의 행을 삽입하는 동안 강제 문제가 있습니다.

df.loc[1] = {'a': 5, 'b': 4.4}
print(df)
#      a    b
# 0  1.0  2.2
# 1  5.0  4.4
print(df.dtypes)
# a    float64
# b    float64
# dtype: object

두 경우 모두 a열을 부동 유형으로 강제 변환하지 않고 정수 유형으로 유지 하려고합니다 .


내가 발견 있지만, 효과적으로 문제가 해결 된 경우 I는 발견 할 수 없었다. 그 동안 나는 당신이 할 수 있다고 생각합니다 :df.loc[[0], df.columns]
Dani Mesejo


pd.DataFrame과 같은 소리가 인스턴스화에서 유형 혼합을 지원하지 않습니까? pandas.pydata.org/pandas-docs/stable/reference/api/… dtype param은 단일 유형 만 지원합니다. .read_[type]여러 dtypes을 지원하지만 ...
Quentin

답변:


4

약간의 파기 후 여기에 끔찍한 추악한 해결책이 있습니다. (더 나은 답변이 허용됩니다.)

여기에서 발견 된 단점 은 숫자가 아닌 열이 강제 변환을 중지한다는 입니다. 따라서 한 행을 다음으로 색인하는 방법이 있습니다 dict.

dict(df.assign(_='').loc[0].drop('_', axis=0))
# {'a': 1, 'b': 2.2}

한 행으로 새 데이터 프레임을 만들어 행 삽입을 수행 할 수 있습니다.

df = df.append(pd.DataFrame({'a': 5, 'b': 4.4}, index=[1]))
print(df)
#    a    b
# 0  1  2.2
# 1  5  4.4

이 두 가지 트릭은 큰 데이터 프레임에 최적화되어 있지 않으므로 더 나은 답변을 주셔서 감사합니다!


당신은 항상 포스트 추가를 강제 할 수 있습니다 df['a'] = df.a.astype(mytype)... 여전히 더럽고 아마도 효율적이지 않습니다.
Quentin

.astype()float-> integer에 위험합니다. 로 변경하는 1.1데 아무런 문제가 없으므로 1수행하기 전에 모든 값이 '정수와 같은지'확인해야합니다. 아마 pd.to_numeric함께 사용 하는 것이 가장 좋습니다downcast='integer'
ALollz

2

문제의 근원은

  1. 팬더 데이터 프레임을 인덱싱하면 팬더 시리즈가 반환됩니다.

우리는 그것을 볼 수 있습니다 :

type(df.loc[0])
# pandas.core.series.Series

그리고 시리즈는 하나의 dtype 만 가질 수 있습니다 (int64 또는 float64).

내 머리에는 두 가지 해결 방법이 있습니다.

print(df.loc[[0]])
# this will return a dataframe instead of series
# so the result will be
#    a    b
# 0  1  2.2

# but the dictionary is hard to read
print(dict(df.loc[[0]]))
# {'a': 0    1
# Name: a, dtype: int64, 'b': 0    2.2
# Name: b, dtype: float64}

또는

print(df.astype(object).loc[0])
# this will change the type of value to object first and then print
# so the result will be
# a      1
# b    2.2
# Name: 0, dtype: object

print(dict(df.astype(object).loc[0]))
# in this way the dictionary is as expected
# {'a': 1, 'b': 2.2}
  1. 사전을 데이터 프레임에 추가하면 사전이 먼저 시리즈 로 변환 된 다음 추가됩니다. (그래서 같은 문제가 다시 발생합니다)

https://github.com/pandas-dev/pandas/blob/master/pandas/core/frame.py#L6973

if isinstance(other, dict):
    other = Series(other)

따라서 귀하의 둘러보기는 실제로 견고한 것입니다.

df.append(pd.Series({'a': 5, 'b': 4.4}, dtype=object, name=1))
#    a    b
# 0  1  2.2
# 1  5  4.4

object데이터 형식 을 사용 하는 것이 좋습니다 ! 다른 하나는 처음부터 DataFrame 객체를 만드는 것입니다.df = pd.DataFrame({'a': [1], 'b': [2.2]}, dtype=object)
Mike T

2

데이터 프레임에서 데이터를 가져 오거나 데이터 프레임에 데이터를 추가하고 데이터 유형을 동일하게 유지해야 할 때마다 필요한 데이터 유형을 인식하지 못하는 다른 내부 구조로 변환하지 마십시오.

그렇게 df.loc[0]하면로 변환됩니다 pd.Series.

>>> type(df.loc[0])
<class 'pandas.core.series.Series'>

그리고 이제는 Series하나만 가질 것 dtype입니다. 따라서 강요 intfloat.

대신 같은 구조를 유지 pd.DataFrame,

>>> type(df.loc[[0]])
<class 'pandas.core.frame.DataFrame'>

프레임으로 필요한 행을 선택한 다음로 변환 dict

>>> df.loc[[0]].to_dict(orient='records')
[{'a': 1, 'b': 2.2}]

마찬가지로 팬더 pd.DataFrame.append기능을 사용하여 새 행을 추가하려면

>>> df = df.append([{'a': 5, 'b': 4.4}]) # NOTE: To append as a row, use []
   a    b
0  1  2.2
0  5  4.4

위의 형식 변환은 발생하지 않습니다.

>>> df.dtypes
a      int64
b    float64
dtype: object

와우는 두 번째 코드 블록을 세 번 읽어야했습니다. 매우 미묘합니다. 이것은 내가 과거에했던 것보다 훨씬 낫습니다 ... 최종 데이터 프레임을 반복하고 올바른 데이터 유형으로 값을 다시 할당하십시오 (그렇습니다. 정확히 확장되지 않는 끔찍한 솔루션입니다).
VanBantam

1
오. 다행이 😊 @VanBantam 도움
Vishnudev

1

약간의 데이터 조작을 통한 다른 접근 방식 :

사전 (또는 데이터 프레임) 목록이 있다고 가정하십시오.

lod=[{'a': [1], 'b': [2.2]}, {'a': [5], 'b': [4.4]}]

여기서 각 사전은 행을 나타냅니다 (두 번째 사전의 목록 참고). 그런 다음 다음을 통해 데이터 프레임을 쉽게 만들 수 있습니다.

pd.concat([pd.DataFrame(dct) for dct in lod])
   a    b
0  1  2.2
0  5  4.4

그리고 열의 유형을 유지합니다. concat 참조

따라서 데이터 프레임과 dicts 목록이 있다면

pd.concat([df] + [pd.DataFrame(dct) for dct in lod])

0

첫 번째 경우 널 입력 가능 정수 데이터 유형으로 작업 할 수 있습니다 . 시리즈 선택이 강요되지 않고 float값이 object컨테이너에 배치됩니다 . 그런 다음 기본 값이로 저장된 사전이 올바르게 작성됩니다 np.int64.

df = pd.DataFrame({'a': [1], 'b': [2.2]})
df['a'] = df['a'].astype('Int64')

d = dict(df.loc[0])
#{'a': 1, 'b': 2.2}

type(d['a'])
#numpy.int64

구문 을 사용하면 두 번째 경우에도 거의 작동하지만으로 업 캐스트 object되므로 좋지 않습니다.

df.loc[1] = {'a': 5, 'b': 4.4}
#   a    b
#0  1  2.2
#1  5  4.4

df.dtypes
#a     object
#b    float64
#dtype: object

그러나 마지막에 행을 추가하는 구문 (RangeIndex 사용)을 약간 변경하면 유형이 올바르게 처리됩니다.

df = pd.DataFrame({'a': [1], 'b': [2.2]})
df['a'] = df['a'].astype('Int64')

df.loc[df.shape[0], :] = [5, 4.4]
#   a    b
#0  1  2.2
#1  5  4.4

df.dtypes
#a      Int64
#b    float64
#dtype: object
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.