sourcecode

중첩된 사전의 항목에서 판다 데이터 프레임 구성

codebag 2023. 7. 17. 20:58
반응형

중첩된 사전의 항목에서 판다 데이터 프레임 구성

구조가 포함된 사전 'user_dict'가 있다고 가정합니다.

  • 레벨 1: 사용자 ID(긴 정수)
  • 레벨 2: 카테고리(문자열)
  • 레벨 3: 다양한 속성(플로트, 인트 등)

예를 들어, 이 사전의 항목은 다음과 같습니다.

user_dict[12] = {
    "Category 1": {"att_1": 1, 
                   "att_2": "whatever"},
    "Category 2": {"att_1": 23, 
                   "att_2": "another"}}

의 각 항목user_dict동일한 구조를 가지고 있으며user_dict에는 속성에서 시리즈를 구성하는 판다 DataFrame에 제공하려는 항목이 많이 포함되어 있습니다.이 경우 계층형 인덱스가 목적에 유용합니다.

특히, 제 질문은 데이터 프레임 생성자가 사전의 "레벨 3" 값으로 시리즈를 구성해야 한다는 것을 이해하는 데 도움이 되는 방법이 있는지 여부입니다.

다음과 같은 작업을 수행할 경우:

df = pandas.DataFrame(users_summary)

"레벨 1"(UserId's)의 항목은 열로 간주되며, 이는 내가 달성하고자 하는 것(UserId's 인덱스 포함)과는 반대입니다.

사전 항목을 반복한 후에 시리즈를 구성할 수 있다는 것을 알지만, 더 직접적인 방법이 있다면 매우 유용할 것입니다.유사한 질문은 파일에 나열된 json 객체에서 판다 데이터 프레임을 구성하는 것이 가능한지 묻는 것입니다.

판다 다중 지수는 튜플 목록으로 구성됩니다.따라서 가장 자연스러운 접근 방식은 입력 딕트의 키가 필요한 다중 인덱스 값에 해당하는 튜플이 되도록 재구성하는 것입니다.그런 다음 다음 다음을 사용하여 데이터 프레임을 구성할 수 있습니다.pd.DataFrame.from_dict옵션 사용orient='index':

user_dict = {12: {'Category 1': {'att_1': 1, 'att_2': 'whatever'},
                  'Category 2': {'att_1': 23, 'att_2': 'another'}},
             15: {'Category 1': {'att_1': 10, 'att_2': 'foo'},
                  'Category 2': {'att_1': 30, 'att_2': 'bar'}}}

pd.DataFrame.from_dict({(i,j): user_dict[i][j] 
                           for i in user_dict.keys() 
                           for j in user_dict[i].keys()},
                       orient='index')


               att_1     att_2
12 Category 1      1  whatever
   Category 2     23   another
15 Category 1     10       foo
   Category 2     30       bar

다른 접근 방식은 구성 요소 데이터 프레임을 연결하여 데이터 프레임을 구성하는 것입니다.

user_ids = []
frames = []

for user_id, d in user_dict.iteritems():
    user_ids.append(user_id)
    frames.append(pd.DataFrame.from_dict(d, orient='index'))

pd.concat(frames, keys=user_ids)

               att_1     att_2
12 Category 1      1  whatever
   Category 2     23   another
15 Category 1     10       foo
   Category 2     30       bar

pd.concat 사전을 허용합니다.이것을 염두에 두고 사전 이해를 사용하여 하위 프레임에 대한 사전 매핑 키를 구축함으로써 단순성과 성능 측면에서 현재 받아들여지고 있는 답변을 개선할 수 있습니다.

pd.concat({k: pd.DataFrame(v).T for k, v in user_dict.items()}, axis=0)

아니면.

pd.concat({
        k: pd.DataFrame.from_dict(v, 'index') for k, v in user_dict.items()
    }, 
    axis=0)

              att_1     att_2
12 Category 1     1  whatever
   Category 2    23   another
15 Category 1    10       foo
   Category 2    30       bar

이 솔루션은 사전 키를 튜플 체인에 평평하게 하여 임의의 깊이에서 작동해야 합니다.

def flatten_dict(nested_dict):
    res = {}
    if isinstance(nested_dict, dict):
        for k in nested_dict:
            flattened_dict = flatten_dict(nested_dict[k])
            for key, val in flattened_dict.items():
                key = list(key)
                key.insert(0, k)
                res[tuple(key)] = val
    else:
        res[()] = nested_dict
    return res


def nested_dict_to_df(values_dict):
    flat_dict = flatten_dict(values_dict)
    df = pd.DataFrame.from_dict(flat_dict, orient="index")
    df.index = pd.MultiIndex.from_tuples(df.index)
    df = df.unstack(level=-1)
    df.columns = df.columns.map("{0[1]}".format)
    return df

다른 사용자가 다중 인덱스 없이 "긴 형식"(리프 값의 유형이 동일)으로 데이터 프레임을 가져오려는 경우 다음 작업을 수행할 수 있습니다.

pd.DataFrame.from_records(
    [
        (level1, level2, level3, leaf)
        for level1, level2_dict in user_dict.items()
        for level2, level3_dict in level2_dict.items()
        for level3, leaf in level3_dict.items()
    ],
    columns=['UserId', 'Category', 'Attribute', 'value']
)

    UserId    Category Attribute     value
0       12  Category 1     att_1         1
1       12  Category 1     att_2  whatever
2       12  Category 2     att_1        23
3       12  Category 2     att_2   another
4       15  Category 1     att_1        10
5       15  Category 1     att_2       foo
6       15  Category 2     att_1        30
7       15  Category 2     att_2       bar

(원래 질문은 (I.) 레벨 1과 2를 다중 인덱스로 하고, 레벨 3을 열로 하고, (II.) 딕트의 값을 반복하는 것 이외의 다른 방법을 묻는 것으로 알고 있습니다.하지만 저는 이 대답이 여전히 적절하고 유용하기를 바랍니다. (I.): 중첩된 받아쓰기를 이 모양으로 만드는 방법을 찾으려고 노력한 저와 같은 사람들에게 그리고 (II.): 다른 대답들도 일부 반복을 포함하고 있고 저는 이 접근법이 유연하고 읽기 쉽다고 생각하기 때문입니다. 하지만 성능에 대해서는 확신할 수 없습니다.)

그래서 저는 사전을 반복하기 위해 for 루프를 사용하곤 했습니다. 하지만 제가 훨씬 더 빨리 작동하는 것은 패널로 변환한 다음 데이터 프레임으로 변환하는 것입니다.당신이 사전을 가지고 있다고 가정해보세요.

import pandas as pd
d
{'RAY Index': {datetime.date(2014, 11, 3): {'PX_LAST': 1199.46,
'PX_OPEN': 1200.14},
datetime.date(2014, 11, 4): {'PX_LAST': 1195.323, 'PX_OPEN': 1197.69},
datetime.date(2014, 11, 5): {'PX_LAST': 1200.936, 'PX_OPEN': 1195.32},
datetime.date(2014, 11, 6): {'PX_LAST': 1206.061, 'PX_OPEN': 1200.62}},
'SPX Index': {datetime.date(2014, 11, 3): {'PX_LAST': 2017.81,
'PX_OPEN': 2018.21},
datetime.date(2014, 11, 4): {'PX_LAST': 2012.1, 'PX_OPEN': 2015.81},
datetime.date(2014, 11, 5): {'PX_LAST': 2023.57, 'PX_OPEN': 2015.29},
datetime.date(2014, 11, 6): {'PX_LAST': 2031.21, 'PX_OPEN': 2023.33}}}

명령어

pd.Panel(d)
<class 'pandas.core.panel.Panel'>
Dimensions: 2 (items) x 2 (major_axis) x 4 (minor_axis)
Items axis: RAY Index to SPX Index
Major_axis axis: PX_LAST to PX_OPEN
Minor_axis axis: 2014-11-03 to 2014-11-06

여기서 pd.패널(d)[항목]이(가) 데이터 프레임을 생성합니다.

pd.Panel(d)['SPX Index']
2014-11-03  2014-11-04  2014-11-05 2014-11-06
PX_LAST 2017.81 2012.10 2023.57 2031.21
PX_OPEN 2018.21 2015.81 2015.29 2023.33

그런 다음 to_frame() 명령을 눌러 데이터 프레임으로 변환할 수 있습니다.또한 reset_index를 사용하여 장축과 단축을 인덱스로 사용하지 않고 열로 변환합니다.

pd.Panel(d).to_frame().reset_index()
major   minor      RAY Index    SPX Index
PX_LAST 2014-11-03  1199.460    2017.81
PX_LAST 2014-11-04  1195.323    2012.10
PX_LAST 2014-11-05  1200.936    2023.57
PX_LAST 2014-11-06  1206.061    2031.21
PX_OPEN 2014-11-03  1200.140    2018.21
PX_OPEN 2014-11-04  1197.690    2015.81
PX_OPEN 2014-11-05  1195.320    2015.29
PX_OPEN 2014-11-06  1200.620    2023.33

마지막으로, 프레임의 모양이 마음에 들지 않으면 패널의 전치 기능을 사용하여 _frame으로 호출하기 전에 모양을 변경할 수 있습니다. 여기 http://pandas.pydata.org/pandas-docs/dev/generated/pandas.Panel.transpose.html 의 설명서를 참조하십시오.

예를 들면,

pd.Panel(d).transpose(2,0,1).to_frame().reset_index()
major        minor  2014-11-03  2014-11-04  2014-11-05  2014-11-06
RAY Index   PX_LAST 1199.46    1195.323     1200.936    1206.061
RAY Index   PX_OPEN 1200.14    1197.690     1195.320    1200.620
SPX Index   PX_LAST 2017.81    2012.100     2023.570    2031.210
SPX Index   PX_OPEN 2018.21    2015.810     2015.290    2023.330

이게 도움이 되길 바랍니다.

검증된 답변을 바탕으로 저에게 가장 효과적인 방법은 다음과 같습니다.

ab = pd.concat({k: pd.DataFrame(v).T for k, v in data.items()}, axis=0)
ab.T

데이터를 표현하는 다른 방법의 경우 많은 작업을 수행할 필요가 없습니다.예를 들어, "외부" 키를 인덱스로, "내부" 키를 열로, 값을 셀 값으로 지정하려면 다음과 같이 합니다.

df = pd.DataFrame.from_dict(user_dict, orient='index')


언급URL : https://stackoverflow.com/questions/13575090/construct-pandas-dataframe-from-items-in-nested-dictionary

반응형