programing

팬더 MultiIndex DataFrame에서 행 선택

goodsources 2022. 10. 10. 18:31
반응형

팬더 MultiIndex DataFrame에서 행 선택

인덱스가 MultiIndex인 데이터 프레임의 행을 선택/필터링하는 가장 일반적인 방법은 무엇입니까?

  • 단일 값/라벨에 기반한 슬라이스
  • 하나 이상의 레벨에서 여러 레이블을 기준으로 슬라이스
  • 부울 조건 및 식 필터링
  • 어떤 방법이 어떤 상황에서 적용 가능한가?

심플화에 관한 전제 조건:

  1. 입력 데이터 프레임에 중복된 인덱스 키가 없습니다.
  2. 아래의 입력 데이터 프레임에는 2개의 레벨만 있습니다.(여기서 나타내는 대부분의 솔루션은 N레벨로 일반화되어 있습니다)

입력 예:

mux = pd.MultiIndex.from_arrays([
    list('aaaabbbbbccddddd'),
    list('tuvwtuvwtuvwtuvw')
], names=['one', 'two'])

df = pd.DataFrame({'col': np.arange(len(mux))}, mux)

         col
one two     
a   t      0
    u      1
    v      2
    w      3
b   t      4
    u      5
    v      6
    w      7
    t      8
c   u      9
    v     10
d   w     11
    t     12
    u     13
    v     14
    w     15

질문 1: 단일 항목 선택

레벨 1에 "a"가 있는 행을 선택하려면 어떻게 해야 합니까?

         col
one two     
a   t      0
    u      1
    v      2
    w      3

또한 출력에서 레벨 1을 드롭하려면 어떻게 해야 합니까?

     col
two     
t      0
u      1
v      2
w      3

1 1b
레벨 "2"의 값이 "t"인 모든 행을 잘라내려면 어떻게 해야 합니까?

         col
one two     
a   t      0
b   t      4
    t      8
d   t     12

질문 2: 레벨 내의 여러 값 선택

레벨 1의 항목 "b" 및 "d"에 해당하는 행을 선택하려면 어떻게 해야 합니까?

         col
one two     
b   t      4
    u      5
    v      6
    w      7
    t      8
d   w     11
    t     12
    u     13
    v     14
    w     15

2 2b
레벨 2의 "t"와 "w"에 해당하는 모든 값을 얻으려면 어떻게 해야 합니까?

         col
one two     
a   t      0
    w      3
b   t      4
    w      7
    t      8
d   w     11
    t     12
    w     15

3: © 3 : 단면 슬라이싱(x, y)

횡단면, 즉 인덱스에 대한 특정 값이 있는 단일 행을 검색하려면 어떻게 해야 합니까?df어떻게 할 수 ('c', 'u')가 .

         col
one two     
c   u      9

4: Sections © 4 : 여러 단면 슬라이스[(a, b), (c, d), ...]

'2'에 하는 두 해야 하나요?('c', 'u') , , , , 입니다.('a', 'w')

         col
one two     
c   u      9
a   w      3

질문 5: 레벨당 1개의 아이템 슬라이스

레벨 "1"의 "a" 또는 레벨 "2"의 "t"에 해당하는 모든 행을 검색하려면 어떻게 해야 합니까?

         col
one two     
a   t      0
    u      1
    v      2
    w      3
b   t      4
    t      8
d   t     12

질문 6: 임의 슬라이스

특정 단면을 슬라이스하려면 어떻게 해야 합니까?"a"와 "b"는 서브레벨 "u"와 "v"를 가진 모든 행을 선택하고 "d"는 서브레벨 "w"를 가진 행을 선택합니다.

         col
one two     
a   u      1
    v      2
b   u      5
    v      6
d   w     11
    w     15

질문 7에서는 숫자 레벨로 구성된 고유한 설정을 사용합니다.

np.random.seed(0)
mux2 = pd.MultiIndex.from_arrays([
    list('aaaabbbbbccddddd'),
    np.random.choice(10, size=16)
], names=['one', 'two'])

df2 = pd.DataFrame({'col': np.arange(len(mux2))}, mux2)

         col
one two     
a   5      0
    0      1
    3      2
    3      3
b   7      4
    9      5
    3      6
    5      7
    2      8
c   4      9
    7     10
d   6     11
    8     12
    8     13
    1     14
    6     15

질문 7: 다중 지수의 개별 수준에서 수치 부등식에 의한 필터링

레벨 2의 값이 5보다 큰 모든 행을 가져오려면 어떻게 해야 합니까?

         col
one two     
b   7      4
    9      5
c   7     10
d   6     11
    8     12
    8     13
    6     15

주의: 이 투고에서는 MultiIndex 작성 방법, MultiIndex에 대한 할당 작업 수행 방법 또는 퍼포먼스 관련 설명에 대해서는 설명하지 않습니다(이러한 내용은 다음에 설명하겠습니다).

MultiIndex / 고급 인덱싱

★★★
은 다음과되어 있습니다.

  1. OP에 제시된 질문에 대해 하나씩 답변합니다.
  2. 각 질문에 대해 이 문제를 해결하고 예상 결과를 얻는 데 적용할 수 있는 방법이 하나 이상 제시됩니다.

추가 기능, 구현 세부 정보 및 주제에 대한 대략적인 기타 정보에 대한 학습에 관심이 있는 독자들을 위해 참고 사항(이것과 거의 유사함)이 포함됩니다.이 노트는 문서를 뒤지고 여러 가지 애매한 특징을 발견함으로써, 그리고 제 경험(인정상 제한된)을 통해 작성되었습니다.

모든 코드 샘플은 팬더 v0.23.4, python3.7에서 생성 및 테스트되었습니다.명확하지 않거나 실제로 올바르지 않은 경우 또는 사용 사례에 적용할 수 있는 솔루션을 찾지 못한 경우 언제든지 수정하거나 의견으로 설명을 요청하거나 새로운 질문을 여십시오.

여기 우리가 자주 다시 방문할 몇 가지 일반적인 사자성어에 대한 소개가 있다.

  1. DataFrame.loc - 슬라이스와 관련된 보다 복잡한 어플리케이션의 경우 라벨(+)을 사용하여 선택하는 일반적인 솔루션

  2. DataFrame.xs - Series/DataFrame에서 특정 단면을 추출합니다.

  3. DataFrame.query - 슬라이스 및/또는 필터링 연산을 동적으로 지정합니다(즉, 동적으로 평가되는 표현식).다른 시나리오보다 일부 시나리오에 더 적합합니다.또한 MultiIndex에 대한 쿼리에 대해서는 문서의 이 섹션을 참조하십시오.

  4. 를 사용하여 생성된 마스크가 있는 부울 인덱싱(특히 여러 값으로 필터링하는 경우)이것은 또한 상황에 따라서는 매우 유용합니다.

주어진 상황에서 무엇이 적용될 수 있는지를 더 잘 이해하기 위해 사구체적 관점에서 다양한 슬라이싱과 필터링 문제를 살펴보는 것이 유익할 것이다.모든 사자성어가 모든 상황에서 똑같이 잘 작동하는 것은 아니라는 것을 이해하는 것이 매우 중요하다.이디옴이 아래 문제에 대한 잠재적인 해결책으로 나열되지 않은 경우, 이디옴을 해당 문제에 효과적으로 적용할 수 없다는 것을 의미합니다.


질문 1

레벨 1에 "a"가 있는 행을 선택하려면 어떻게 해야 합니까?

         col
one two     
a   t      0
    u      1
    v      2
    w      3

하시면 됩니다.loc대부분의 상황에 적용할 수 있는 범용 솔루션:

df.loc[['a']]

이 시점에서, 만약 당신이

TypeError: Expected tuple, got str

그것은 당신이 오래된 버전의 판다를 사용하고 있다는 것을 의미합니다.아아아! 이외의 경우는, 「 」, 「 」를 사용합니다.df.loc[('a', slice(None)), :].

외에 '먹다'를 사용할 .xs 」에 주의주세요.levels ★★★★★★★★★★★★★★★★★」axisarguments (인수)

df.xs('a', level=0, axis=0, drop_level=False)
# df.xs('a', drop_level=False)

에서는, 「」, 「」.drop_level=False는 인수가 인수가 되지 .xs1레벨을 떨어뜨린 결과(슬라이스한 레벨)로부터 해방됩니다.

또 은 '먹다'를 사용하는 예요.query:

df.query("one == 'a'")

을 "이름이 없습니다"로."ilevel_0 == 'a'".

""를 사용합니다.get_level_values:

df[df.index.get_level_values('one') == 'a']
# If your levels are unnamed, or if you need to select by position (not label),
# df[df.index.get_level_values(0) == 'a']

또한 출력에서 레벨 1을 드롭하려면 어떻게 해야 합니까?

     col
two     
t      0
u      1
v      2
w      3

이것은, 다음의 어느쪽인가를 사용해 간단하게 실시할 수 있습니다.

df.loc['a'] # Notice the single string argument instead the list.

아니면...

df.xs('a', level=0, axis=0, drop_level=True)
# df.xs('a')

「 」는 할 수 해 주세요.drop_level)True★★★★★★★★★★★★★★★★★★」

★★★
데이터 프레임을 인쇄할 때 표시되지 않더라도 필터링된 데이터 프레임에 모든 레벨이 있을 수 있습니다.를 들어 '예'라고 하면,

v = df.loc[['a']]
print(v)
         col
one two     
a   t      0
    u      1
    v      2
    w      3

print(v.index)
MultiIndex(levels=[['a', 'b', 'c', 'd'], ['t', 'u', 'v', 'w']],
           labels=[[0, 0, 0, 0], [0, 1, 2, 3]],
           names=['one', 'two'])

이러한 레벨은, 다음과 같이 삭제할 수 있습니다.

v.index = v.index.remove_unused_levels()
print(v.index)
MultiIndex(levels=[['a'], ['t', 'u', 'v', 'w']],
           labels=[[0, 0, 0, 0], [0, 1, 2, 3]],
           names=['one', 'two'])

질문 1b

레벨 "2"의 값이 "t"인 모든 행을 잘라내려면 어떻게 해야 합니까?

         col
one two     
a   t      0
b   t      4
    t      8
d   t     12

직감적으로 다음과 같은 것이 필요합니다.

df.loc[(slice(None), 't'), :]

'어!' ™ '어!' 해서 보다 수 .pd.IndexSliceAPI를 사용합니다.

idx = pd.IndexSlice
df.loc[idx[:, 't'], :]

이게 훨씬, 훨씬 깨끗해.

★★★
슬라이스는 왜 '''가 거죠?:요한한 체체 체? ???하면 this this this this 。loc축을 따라 및를 수행할 수 (선택 및 슬라이스).axis=0 ★★★★★★★★★★★★★★★★★」axis=1슬라이싱이 어느 축에서 이루어지는지를 명확히 하지 않으면 조작이 애매해진다.슬라이스에 대한 설명서의 빨간색 큰 상자를 참조하십시오.

,.locaxis★★★★★★★★★★★★★★★★★★:

df.loc(axis=0)[pd.IndexSlice[:, 't']]

axis 「」( 「」, 「」df.loc[pd.IndexSlice[:, 't']]에 있는 되며, a ) 、 、 、 ), 、 슬 、 슬 、 슬 、 슬 、 ), 、 ), 、 ), 、 ), 、 ), ), 、KeyError을 사용하다

이것은 슬라이서에 기록되어 있습니다.다만, 이 투고에서는, 모든 축을 명시적으로 지정합니다.

★★★★★★★★★★★★★★★★ xs, 그렇습니다.

df.xs('t', axis=0, level=1, drop_level=False)

★★★★★★★★★★★★★★★★ query, 그렇습니다.

df.query("two == 't'")
# Or, if the first level has no name, 
# df.query("ilevel_1 == 't'") 

마지막으로 ★★★★★★★★★★★★★★★★★★★★★★★★★★.get_level_values 해도

df[df.index.get_level_values('two') == 't']
# Or, to perform selection by position/integer,
# df[df.index.get_level_values(1) == 't']

모두 같은 취지의.


질문 2

레벨 1의 항목 "b" 및 "d"에 해당하는 행을 선택하려면 어떻게 해야 합니까?

         col
one two     
b   t      4
    u      5
    v      6
    w      7
    t      8
d   w     11
    t     12
    u     13
    v     14
    w     15

loc를 사용하면 목록을 지정하는 것과 유사한 방식으로 수행됩니다.

df.loc[['b', 'd']]

위의 "b" 및 "d" 선택 문제를 해결하려면 다음을 사용할 수도 있습니다.query:

items = ['b', 'd']
df.query("one in @items")
# df.query("one == @items", parser='pandas')
# df.query("one in ['b', 'd']")
# df.query("one == ['b', 'd']", parser='pandas')

★★★
네, 기본 파서는 다음과 같습니다.'pandas'단, 이 구문은 python이 아닌 것을 강조하는 것이 중요합니다.판다 파서는 표현과는 약간 다른 해석 트리를 생성합니다.이는 일부 작업을 보다 직관적으로 지정할 수 있도록 하기 위해 수행됩니다.자세한 내용은 pd.eval()사용한 판다의 동적 표현 평가에 관한 제 글을 읽어주세요.

★★★★★★★★★★★★★★★★.get_level_values+Index.isin:

df[df.index.get_level_values("one").isin(['b', 'd'])]

질문 2b

레벨 2의 "t"와 "w"에 해당하는 모든 값을 얻으려면 어떻게 해야 합니까?

         col
one two     
a   t      0
    w      3
b   t      4
    w      7
    t      8
d   w     11
    t     12
    w     15

★★★★★★★★★★★★★★★★ loc, 이것은, 와의 조합만으로 가능합니다.pd.IndexSlice.

df.loc[pd.IndexSlice[:, ['t', 'w']], :] 

번째 콜론:pd.IndexSlice[:, ['t', 'w']]첫 번째 레벨을 가로질러 슬라이스하는 것을 의미합니다.쿼리되는 레벨의 깊이가 증가함에 따라 슬라이스할 레벨당 하나씩 더 많은 슬라이스를 지정해야 합니다.단, 슬라이스되는 수준보다 더 많은 수준을 지정할 필요는 없습니다.

★★★★★★★★★★★★★★★★ query은, 「이것」입니다.

items = ['t', 'w']
df.query("two in @items")
# df.query("two == @items", parser='pandas') 
# df.query("two in ['t', 'w']")
# df.query("two == ['t', 'w']", parser='pandas')

★★★★★★★★★★★★★★★★ get_level_values ★★★★★★★★★★★★★★★★★」Index.isin(음악) :

df[df.index.get_level_values('two').isin(['t', 'w'])]

질문 3

횡단면, 즉 인덱스에 대한 특정 값이 있는 단일 행을 검색하려면 어떻게 해야 합니까?df어떻게 할 수 ('c', 'u')가 .

         col
one two     
c   u      9

loc합니다.

df.loc[('c', 'u'), :]

아니면...

df.loc[pd.IndexSlice[('c', 'u')]]

★★★
이 시점에서, 다음과 같은 에 부딪힐 수 있습니다.

PerformanceWarning: indexing past lexsort depth may impact performance.

이것은 인덱스가 정렬되지 않았다는 것을 의미합니다.판다는 최적의 검색과 검색을 위해 인덱스 정렬(이 경우 문자열 값을 취급하기 때문에 사전 편찬적으로)에 의존합니다.빠른 해결 방법은 를 사용하여 Data Frame을 미리 정렬하는 것입니다.이러한 쿼리를 여러 개 동시에 수행할 계획인 경우 성능 관점에서 특히 유용합니다.

df_sort = df.sort_index()
df_sort.loc[('c', 'u')]

를 사용하여 인덱스가 정렬되었는지 확인할 수도 있습니다.이 함수는 반환됩니다.True ★★★★★★★★★★★★★★★★★」False 여부를 할 수 .이 함수를 호출하여 추가 정렬 단계가 필요한지 여부를 결정할 수 있습니다.

★★★★★★★★★★★★★★★★ xs이는 다시 단순히 단일 태플을 첫 번째 인수로 전달하고 다른 모든 인수는 적절한 기본값으로 설정됩니다.

df.xs(('c', 'u'))

★★★★★★★★★★★★★★★★ query

df.query("one == 'c' and two == 'u'")

이 문제를 일반화하기가 상대적으로 어렵다는 것을 알 수 있습니다.하지만 이 문제는 여전히 괜찮습니다.

레벨에 에서는, 「 」는 「 」를 참조해 주세요.get_level_values수 되지 않습니다.

m1 = (df.index.get_level_values('one') == 'c')
m2 = (df.index.get_level_values('two') == 'u')
df[m1 & m2]

질문 4

'2'에 하는 두 해야 하나요?('c', 'u') , , , , 입니다.('a', 'w')

         col
one two     
c   u      9
a   w      3

★★★★★★★★★★★★★★★★ loc도 간단해요

df.loc[[('c', 'u'), ('a', 'w')]]
# df.loc[pd.IndexSlice[[('c', 'u'), ('a', 'w')]]]

★★★★★★★★★★★★★★★★ query단면 및 레벨에 걸쳐 반복함으로써 쿼리 문자열을 동적으로 생성해야 합니다.

cses = [('c', 'u'), ('a', 'w')]
levels = ['one', 'two']
# This is a useful check to make in advance.
assert all(len(levels) == len(cs) for cs in cses) 

query = '(' + ') or ('.join([
    ' and '.join([f"({l} == {repr(c)})" for l, c in zip(levels, cs)]) 
    for cs in cses
]) + ')'

print(query)
# ((one == 'c') and (two == 'u')) or ((one == 'a') and (two == 'w'))

df.query(query)

100% 추천하지 마세요! 하지만 가능합니다.

레벨이 여러 개인 경우는 어떻게 해야 하나요?
이 시나리오의 옵션 중 하나는 체크하지 않은 레벨을 드롭하고 멤버쉽을 테스트하고 최종 결과에서 부울 인덱스를 사용하는 것입니다.

df[df.index.droplevel(unused_level).isin([('c', 'u'), ('a', 'w')])]

질문 5

레벨 "1"의 "a" 또는 레벨 "2"의 "t"에 해당하는 모든 행을 검색하려면 어떻게 해야 합니까?

         col
one two     
a   t      0
    u      1
    v      2
    w      3
b   t      4
    t      8
d   t     12

은 사실 입니다.loc정확성을 유지하면서 코드를 선명하게 유지합니다. df.loc[pd.IndexSlice['a', 't']] 틀렸다, 틀렸다, 틀렸다, 틀렸다, 됩니다.df.loc[pd.IndexSlice[('a', 't')]](예: 면 ( 、 ( ( ( ( (). 하다, 하다, 하다, 하다, 하다, 하다, 하다, 하다, 하다, 하다, 하다, 하다, 이런 식으로 할 수 .pd.concat각 라벨을 개별적으로 취급합니다.

pd.concat([
    df.loc[['a'],:], df.loc[pd.IndexSlice[:, 't'],:]
])

         col
one two     
a   t      0
    u      1
    v      2
    w      3
    t      0   # Does this look right to you? No, it isn't!
b   t      4
    t      8
d   t     12

행 중 하나가 중복되어 있는 것을 알 수 있습니다.그 행은 두 슬라이스 조건을 모두 만족시켜 두 번 나타났기 때문입니다.대신 당신이 할 필요가 있습니다.

v = pd.concat([
        df.loc[['a'],:], df.loc[pd.IndexSlice[:, 't'],:]
])
v[~v.index.duplicated()]

그러나 DataFrame에 (원하는) 중복 인덱스가 본질적으로 포함되어 있는 경우, 이러한 인덱스는 유지되지 않습니다.극히 주의하여 사용하십시오.

★★★★★★★★★★★★★★★★ query이치노

df.query("one == 'a' or two == 't'")

★★★★★★★★★★★★★★★★ get_level_values이것은 아직 심플하지만 우아하지는 않습니다.

m1 = (df.index.get_level_values('one') == 'a')
m2 = (df.index.get_level_values('two') == 't')
df[m1 | m2] 

질문 6

특정 단면을 슬라이스하려면 어떻게 해야 합니까?"a"와 "b"는 서브레벨 "u"와 "v"를 가진 모든 행을 선택하고 "d"는 서브레벨 "w"를 가진 행을 선택합니다.

         col
one two     
a   u      1
    v      2
b   u      5
    v      6
d   w     11
    w     15

이것은 4가지 이디옴의 적용 가능성을 이해하기 위해 추가한 특별한 케이스입니다. 슬라이스가 매우 구체적이고 실제 패턴을 따르지 않기 때문에 어느 것도 효과적으로 작동하지 않습니다.

는 키 .loc이를 위한 한 가지 방법은 다음과 같습니다.

keys = [('a', 'u'), ('a', 'v'), ('b', 'u'), ('b', 'v'), ('d', 'w')]
df.loc[keys, :]

는, 「 「 및 서브 것을 해, 과 「a」, 「b」, 「b」로 나눌 수 .concat★★★★

pd.concat([
     df.loc[(('a', 'b'), ('u', 'v')), :], 
     df.loc[('d', 'w'), :]
   ], axis=0)

의 슬라이스 은 "a"와 "b"가 더 깨끗합니다.(('a', 'b'), ('u', 'v'))각 레벨에 대해 색인화되는 동일한 하위 항목이 동일하기 때문입니다.


질문 7

레벨 2의 값이 5보다 큰 모든 행을 가져오려면 어떻게 해야 합니까?

         col
one two     
b   7      4
    9      5
c   7     10
d   6     11
    8     12
    8     13
    6     15

할 수 요, 이렇게 하다, 하다, 하다, 하다, 이렇게.query ,

df2.query("two > 5")

★★★★★★★★★★★★★★★★★.get_level_values.

df2[df2.index.get_level_values('two') > 5]

★★★
이 예시와 마찬가지로 이러한 구성을 사용하여 임의의 조건에 따라 필터링할 수 있습니다.'아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, loc ★★★★★★★★★★★★★★★★★」xs는 라벨 의 인덱싱 전용으로, 「의 인덱스 작성」은 「라벨 베이스의 인덱스 작성」입니다.query ★★★★★★★★★★★★★★★★★」get_level_values는 필터링을 위한 일반적인 조건부 마스크를 작성하는 데 도움이 됩니다.


보너스 질문

, 자르다, 자르다, 자르다, 자르다, 자르다, 자르다, 자르다, 자르다, , 자르다, 자르다, 자르다, 자르다, 자르다, 자르다, 자르다.MultiIndex ?

실제로 여기서의 솔루션은 열에도 적용할 수 있습니다.단, 약간의 변경도 마찬가지입니다.고려사항:

np.random.seed(0)
mux3 = pd.MultiIndex.from_product([
        list('ABCD'), list('efgh')
], names=['one','two'])

df3 = pd.DataFrame(np.random.choice(10, (3, len(mux))), columns=mux3)
print(df3)

one  A           B           C           D         
two  e  f  g  h  e  f  g  h  e  f  g  h  e  f  g  h
0    5  0  3  3  7  9  3  5  2  4  7  6  8  8  1  6
1    7  7  8  1  5  9  8  9  4  3  0  3  5  0  2  3
2    8  1  3  3  3  7  0  1  9  9  0  4  7  3  2  7

다음은 4개의 이디옴을 열로 작동시키기 위해 변경해야 할 사항입니다.

  1. loc, 사용

     df3.loc[:, ....] # Notice how we slice across the index with `:`. 
    

    또는,

     df3.loc[:, pd.IndexSlice[...]]
    
  2. 「」를 xs에 따라서, 「인수」, 「인수」를 주세요.axis=1.

  3. 액세스 할 수 .df.columns.get_level_values ', 하다, 하다, 하다, 이런 거.

     df.loc[:, {condition}] 
    

    서 ★★★★★{condition}는 을 사용하여 .columns.get_level_values.

  4. 「」를 query유일한 옵션은 다음과 같이 전치하고 인덱스를 조회한 후 다시 전치하는 것입니다.

     df3.T.query(...).T
    

    권장하지 않습니다. 다른 3가지 옵션 중 하나를 사용하십시오.

최근에 우연히 3+레벨의 멀티 인덱스 데이터 프레임에서 위의 어떤 솔루션에서도 원하는 결과를 얻을 수 없는 사용 사례를 발견했습니다.물론 위의 솔루션이 제 사용 사례에 효과가 있을 가능성이 높으며, 저는 몇 가지 시도를 해봤지만, 가능한 시간 내에 작업을 수행할 수 없었습니다.

저는 전문가와는 거리가 먼 사람입니다만, 위의 포괄적인 답변에 기재되어 있지 않은 솔루션을 우연히 발견했습니다.솔루션이 최적이라는 보장은 없습니다.

이것은, 상기의 질문 #6에 대해서 약간 다른 결과를 얻을 수 있는 다른 방법입니다.(다른 질문도 마찬가지일 가능성이 있습니다)

특히 찾고 있던 것은 다음과 같습니다.

  1. 한 지수 수준에서 두 개 이상의 값을 선택하고 다른 지수 수준에서 단일 값을 선택하는 방법
  2. 이전 조작의 인덱스 값을 데이터 프레임 출력에 남기는 방법.

기어의 몽키 렌치(완전히 고정 가능하지만):

  1. 인덱스에 이름이 없습니다.

아래 장난감 데이터 프레임:

    index = pd.MultiIndex.from_product([['a','b'],
                               ['stock1','stock2','stock3'],
                               ['price','volume','velocity']])

    df = pd.DataFrame([1,2,3,4,5,6,7,8,9,
                      10,11,12,13,14,15,16,17,18], 
                       index)

                        0
    a stock1 price      1
             volume     2
             velocity   3
      stock2 price      4
             volume     5
             velocity   6
      stock3 price      7
             volume     8
             velocity   9
    b stock1 price     10
             volume    11
             velocity  12
      stock2 price     13
             volume    14
             velocity  15
      stock3 price     16
             volume    17
             velocity  18

물론 다음 방법을 사용하면 됩니다.

    df.xs(('stock1', 'velocity'), level=(1,2))

        0
    a   3
    b  12

하지만 저는 다른 결과를 원했기 때문에 그 결과를 얻기 위한 방법은 다음과 같습니다.

   df.iloc[df.index.isin(['stock1'], level=1) & 
           df.index.isin(['velocity'], level=2)] 

                        0
    a stock1 velocity   3
    b stock1 velocity  12

또한 한 레벨에서 두 개 이상의 값과 다른 레벨에서 단일(또는 두 개 이상의) 값을 원하는 경우:

    df.iloc[df.index.isin(['stock1','stock3'], level=1) & 
            df.index.isin(['velocity'], level=2)] 

                        0
    a stock1 velocity   3
      stock3 velocity   9
    b stock1 velocity  12
      stock3 velocity  18

위의 방법은 다소 서투른 것 같습니다만, 제 욕구를 충족시키고, 보너스로는 이해하고 읽기 쉬웠기 때문입니다.

이것은 dfsql에 적합한 케이스로 보입니다.

df.sql(<SQL select statement>)

https://github.com/mindsdb/dfsql

자세한 내용은 여기를 참조하십시오.

https://medium.com/riselab/why-every-data-scientist-using-pandas-needs-modin-bringing-sql-to-dataframes-3b216b29a7c0

저는 이 질문을 오랫동안 사용해 왔고, 매우 철저하고 모든 인스턴스를 처리하는 @cs95의 답변에 감사드립니다.@r-a의 답변과 마찬가지로 저도 여러 레벨을 포함하는 여러 인덱스로 작업할 수 있는 방법을 찾고 싶었습니다.

나는 마침내 위에서 제안한 몇 가지 질문을 처리할 수 있는 수준 또는 명명된 인덱스가 주어진 임의의 수의 슬라이스를 얻을 수 있는 방법을 찾았다.서의 큰 입니다.slice(None) ★★★:pd.IndexSlice여러 인덱스 또는 슬라이스에 사용할 수 있습니다.

import pandas as pd

def slice_df_by(df_, slice_by=["Oman", "Nairobi",], slice_idx='country'):
    idxn = df_.index.names.index(slice_idx)
    return df_.loc[tuple([slice(None)]*idxn +[slice_by] ), :]

gender = tuple(["male", "female"]*6)
thrown = tuple(["rock", "scissors", "paper"]*4) 
country = tuple(["Nairobi", "Oman", "Djibouti", "Belize"]*3) 
names = tuple(["Chris", "Pat", "Michele", "Thomy", "Musa", "Casey"]*2)

tuples = list(zip(gender, thrown, country, names))

idx = pd.MultiIndex.from_tuples(tuples, 
                                names=["gender", "thrown", "country", "name"])

df = pd.DataFrame({'Count A': [12., 70., 30., 20.]*3, 
                   'Count B': [12., 70., 30., 20.]*3}, index=idx)

에 할 수 입니다.slice_df_by인덱스 이름과 값 목록만 사용하면서 더 복잡한 슬라이스를 가져옵니다.

print(slice_df_by(df))

                                 Count A  Count B
gender thrown   country name                     
female scissors Oman    Pat         70.0     70.0
       paper    Oman    Casey       70.0     70.0
       rock     Oman    Thomy       70.0     70.0
male   rock     Nairobi Chris       12.0     12.0
       scissors Nairobi Musa        12.0     12.0
       paper    Nairobi Michele     12.0     12.0

@r-a가 지적한 바와 같이 캐치는 명명된 인덱스가 없는 것입니다.여기의 접근방식을 사용하여 이를 충족시킬 수 있는 방법은 여러 가지가 있습니다.df.index.names = ["names", "for", "the", "indices"]'이것'은 다음과 같습니다.

idxz = lambda ixln=4: [chr(i) for i in np.arange(ixln)+65]
df.index.names = idxz(len(df.index.names))
print(idxz())
Out[132]: ['A', 'B', 'C', 'D']

언급URL : https://stackoverflow.com/questions/53927460/select-rows-in-pandas-multiindex-dataframe

반응형