Pandas DataFrame의 하위 클래스에 대한 속성 설정 기


9

pd.DataFrame( grouptimestamp_col)를 초기화 할 때 두 개의 필수 인수가 있는 하위 클래스를 설정하려고합니다 . 나는 그 주장에 대한 유효성 검사를 실행할 grouptimestamp_col나는 각 속성에 대한 setter 메소드를 가지고, 그래서. 이 모든 시도 set_index()하고 얻을 때까지 작동합니다 TypeError: 'NoneType' object is not iterable. 어떤 인수가 내 setter 함수에 전달되고 있지 표시 test_set_index하고 test_assignment_with_indexed_obj. if g == None: returnsetter 함수에 추가 하면 테스트 사례를 통과 할 수 있지만 이것이 올바른 해결책이라고 생각하지 않습니다.

이러한 필수 인수에 대한 특성 유효성 검증을 어떻게 구현해야합니까?

아래는 내 수업입니다.

import pandas as pd
import numpy as np


class HistDollarGains(pd.DataFrame):
    @property
    def _constructor(self):
        return HistDollarGains._internal_ctor

    _metadata = ["group", "timestamp_col", "_group", "_timestamp_col"]

    @classmethod
    def _internal_ctor(cls, *args, **kwargs):
        kwargs["group"] = None
        kwargs["timestamp_col"] = None
        return cls(*args, **kwargs)

    def __init__(
        self,
        data,
        group,
        timestamp_col,
        index=None,
        columns=None,
        dtype=None,
        copy=True,
    ):
        super(HistDollarGains, self).__init__(
            data=data, index=index, columns=columns, dtype=dtype, copy=copy
        )

        self.group = group
        self.timestamp_col = timestamp_col

    @property
    def group(self):
        return self._group

    @group.setter
    def group(self, g):
        if g == None:
            return

        if isinstance(g, str):
            group_list = [g]
        else:
            group_list = g

        if not set(group_list).issubset(self.columns):
            raise ValueError("Data does not contain " + '[' + ', '.join(group_list) + ']')
        self._group = group_list

    @property
    def timestamp_col(self):
        return self._timestamp_col

    @timestamp_col.setter
    def timestamp_col(self, t):
        if t == None:
            return
        if not t in self.columns:
            raise ValueError("Data does not contain " + '[' + t + ']')
        self._timestamp_col = t

내 테스트 사례는 다음과 같습니다.

import pytest

import pandas as pd
import numpy as np

from myclass import *


@pytest.fixture(scope="module")
def sample():
    samp = pd.DataFrame(
        [
            {"timestamp": "2020-01-01", "group": "a", "dollar_gains": 100},
            {"timestamp": "2020-01-01", "group": "b", "dollar_gains": 100},
            {"timestamp": "2020-01-01", "group": "c", "dollar_gains": 110},
            {"timestamp": "2020-01-01", "group": "a", "dollar_gains": 110},
            {"timestamp": "2020-01-01", "group": "b", "dollar_gains": 90},
            {"timestamp": "2020-01-01", "group": "d", "dollar_gains": 100},
        ]
    )

    return samp

@pytest.fixture(scope="module")
def sample_obj(sample):
    return HistDollarGains(sample, "group", "timestamp")

def test_constructor_without_args(sample):
    with pytest.raises(TypeError):
        HistDollarGains(sample)


def test_constructor_with_string_group(sample):
    hist_dg = HistDollarGains(sample, "group", "timestamp")
    assert hist_dg.group == ["group"]
    assert hist_dg.timestamp_col == "timestamp"


def test_constructor_with_list_group(sample):
    hist_dg = HistDollarGains(sample, ["group", "timestamp"], "timestamp")

def test_constructor_with_invalid_group(sample):
    with pytest.raises(ValueError):
        HistDollarGains(sample, "invalid_group", np.random.choice(sample.columns))

def test_constructor_with_invalid_timestamp(sample):
    with pytest.raises(ValueError):
        HistDollarGains(sample, np.random.choice(sample.columns), "invalid_timestamp")

def test_assignment_with_indexed_obj(sample_obj):
    b = sample_obj.set_index(sample_obj.group + [sample_obj.timestamp_col])

def test_set_index(sample_obj):
    # print(isinstance(a, pd.DataFrame))
    assert sample_obj.set_index(sample_obj.group + [sample_obj.timestamp_col]).index.names == ['group', 'timestamp']

1
속성 None값이 유효하지 않은 경우 ? group를 올리면 안됩니다 ValueError.
chepner

1
당신은 옳지 None않은 가치입니다. 그래서 if 문을 좋아하지 않습니다. 그러나 None을 추가하면 테스트를 통과합니다. None if 문없이이를 올바르게 수정하는 방법을 찾고 있습니다.
cpage

2
세터는를 올려야합니다 ValueError. 문제는 우선 group속성을 무엇으로 설정하려고하는지 알아내는 것입니다 None.
chepner

@chepner 네, 맞습니다.
cpage

Pandas Flavor 패키지가 도움이 될 수 있습니다.
Mykola Zotko

답변:


3

set_index()메소드는 self.copy()내부적으로 호출 하여 DataFrame 객체의 복사본을 생성하고 ( 여기 에서 소스 코드 참조 ) 사용자 정의 생성자 메서드 _internal_ctor()를 사용하여 새 객체 ( source ) 를 생성합니다 . 참고 self._constructor()로 동일 self._internal_ctor()깊은 복사 또는 슬라이스 등의 작업을 수행하는 동안 새로운 인스턴스를 생성 해 거의 모든 팬더 클래스에 대한 일반적인 내부 방법이다. 문제는 실제로이 기능에서 비롯됩니다.

class HistDollarGains(pd.DataFrame):
    ...
    @classmethod
    def _internal_ctor(cls, *args, **kwargs):
        kwargs["group"]         = None
        kwargs["timestamp_col"] = None
        return cls(*args, **kwargs) # this is equivalent to calling
                                    # HistDollarGains(data, group=None, timestamp_col=None)

github 문제 에서이 코드를 복사 한 것 같습니다 . 행 kwargs["**"] = None은 생성자에게 명시 적으로 와 로 설정 None하도록 지시합니다 . 마지막으로 setter / validator가 새 값으로 설정 되어 오류가 발생합니다.grouptimestamp_colNone

따라서 허용 가능한 값을 groupand로 설정해야합니다 timestamp_col.

    @classmethod
    def _internal_ctor(cls, *args, **kwargs):
        kwargs["group"]         = []
        kwargs["timestamp_col"] = 'timestamp' # or whatever name that makes your validator happy
        return cls(*args, **kwargs)

그런 다음 if g == None: return유효성 검사기 에서 줄을 삭제할 수 있습니다 .

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