Pandas 데이터 프레임의 맞춤 정렬


89

열에 월 이름이 포함 된 Python pandas 데이터 프레임이 있습니다.

예를 들어 사전을 사용하여 사용자 정의 정렬을 수행하려면 어떻게해야합니까?

custom_dict = {'March':0, 'April':1, 'Dec':3}  

1
열에 월 이름이 포함되어 있다는 것은 월 이름을 포함하는 열 (내 대답)이 있거나 열 이름이 월 이름 (음미로)으로 많은 열이 있음을 의미합니까?
Andy Hayden

1
허용되는 답변은 구식이며 pd.Categorical기본적으로 정렬 된 카테고리를 해석하지 않기 때문에 기술적으로도 정확 하지 않습니다. 이 답변을 참조하십시오 .
cs95

답변:


141

Pandas 0.15는 Categorical Series를 도입 하여 훨씬 더 명확한 방법을 제공합니다.

먼저 월 열을 범주 형으로 만들고 사용할 순서를 지정합니다.

In [21]: df['m'] = pd.Categorical(df['m'], ["March", "April", "Dec"])

In [22]: df  # looks the same!
Out[22]:
   a  b      m
0  1  2  March
1  5  6    Dec
2  3  4  April

이제 월 열을 정렬하면 해당 목록을 기준으로 정렬됩니다.

In [23]: df.sort_values("m")
Out[23]:
   a  b      m
0  1  2  March
2  3  4  April
1  5  6    Dec

참고 : 값이 목록에 없으면 NaN으로 변환됩니다.


관심있는 사람들을위한 오래된 답변 ...

중개 시리즈를 만들 수 있습니다 set_index.

df = pd.DataFrame([[1, 2, 'March'],[5, 6, 'Dec'],[3, 4, 'April']], columns=['a','b','m'])
s = df['m'].apply(lambda x: {'March':0, 'April':1, 'Dec':3}[x])
s.sort_values()

In [4]: df.set_index(s.index).sort()
Out[4]: 
   a  b      m
0  1  2  March
1  3  4  April
2  5  6    Dec

언급했듯이 최신 팬더에서 Series에는 replace이 작업을 더 우아하게 수행 하는 방법이 있습니다.

s = df['m'].replace({'March':0, 'April':1, 'Dec':3})

약간의 차이점은 딕셔너리 외부에 값이 있으면이 값이 증가하지 않는다는 것입니다 (단지 동일하게 유지됨).


s = df['m'].replace({'March':0, 'April':1, 'Dec':3})뿐만 아니라 라인이 작동 - 바로 나 같은 사람이 학습 팬더을 위해
kdauria

@kdauria 좋은 자리! (내가이 글을 쓴 이후로 오랜 시간이 걸렸습니다!) 확실히 최선의 옵션을 바꾸고, 또 다른 방법은 다음을 사용하는 것입니다. .apply({'March':0, 'April':1, 'Dec':3}.get):) 0.15에서는 범주 계열 / 열이 있으므로 가장 좋은 방법은이를 사용하고 정렬이 작동합니다.
Andy Hayden 2014 년

@AndyHayden 저는 두 번째 줄을 '바꾸기'방법으로 자유롭게 대체했습니다. 괜찮 았으면 좋겠어요.
Faheem Mitha

@AndyHayden 편집이 거부되었지만 여전히 합리적인 변경이라고 생각합니다.
Faheem Mitha

7
df.sort_values("m")(대신 df.sort("m")) 최신 팬더에서 사용하는지 확인하십시오 . 그렇지 않으면 AttributeError: 'DataFrame' object has no attribute 'sort';)가 표시됩니다.
브레인 스토밍

17

판다> = 1.1

곧 인수 sort_values와 함께 사용할 수 있습니다 key.

pd.__version__
# '1.1.0.dev0+2004.g8d10bfb6f'

custom_dict = {'March': 0, 'April': 1, 'Dec': 3} 
df

   a  b      m
0  1  2  March
1  5  6    Dec
2  3  4  April

df.sort_values(by=['m'], key=lambda x: x.map(custom_dict))

   a  b      m
0  1  2  March
2  3  4  April
1  5  6    Dec

key인수는 입력 할 시리즈 반환 시리즈로합니다. 이 시리즈는 내부적으로 argsorted이며 정렬 된 인덱스는 입력 DataFrame을 재정렬하는 데 사용됩니다. 정렬 할 열이 여러 개인 경우 키 기능이 차례로 각 열에 적용됩니다. 키로 정렬을 참조하십시오 .


판다 <= 1.0.X

하나의 간단한 방법은 출력을 사용하고 Series.mapSeries.argsort에 색인을 df사용하여 DataFrame.iloc(이 정렬 argsort 정수 위치를 생성 이후); 당신은 사전을 가지고 있기 때문에; 이것은 쉬워집니다.

df.iloc[df['m'].map(custom_dict).argsort()]

   a  b      m
0  1  2  March
2  3  4  April
1  5  6    Dec

내림차순 으로 정렬해야하는 경우 매핑을 반전합니다.

df.iloc[(-df['m'].map(custom_dict)).argsort()]

   a  b      m
1  5  6    Dec
2  3  4  April
0  1  2  March

이것은 숫자 항목에서만 작동합니다. 그렇지 않으면을 사용 sort_values하고 색인에 액세스 하여이 문제를 해결해야합니다 .

df.loc[df['m'].map(custom_dict).sort_values(ascending=False).index]

   a  b      m
1  5  6    Dec
2  3  4  April
0  1  2  March

또는에서 더 많은 옵션을 사용할 수 있지만 ( astype지금은 더 이상 사용되지 않음), 올바르게 작동 pd.Categorical하도록 지정해야 합니다 .ordered=True

# Older version,
# df['m'].astype('category', 
#                categories=sorted(custom_dict, key=custom_dict.get), 
#                ordered=True)
df['m'] = pd.Categorical(df['m'], 
                         categories=sorted(custom_dict, key=custom_dict.get), 
                         ordered=True)

이제 간단한 sort_values호출이 트릭을 수행합니다.

df.sort_values('m')
 
   a  b      m
0  1  2  March
2  3  4  April
1  5  6    Dec

groupby출력을 정렬 할 때도 범주 순서가 적용됩니다 .


2
당신은 이미 그것을 강조했지만 다른 누군가가 그것을 훑어보고 놓칠 경우를 대비하여 반복하고 싶습니다 : Pandas Categorical은 ordered=None기본적으로 설정합니다. 설정하지 않으면 주문이 잘못되거나 V23에서 중단됩니다. 특히 Max 함수는 TypeError를 제공합니다 (Categorical은 작업 max에 대해 정렬되지 않음).
Dave Liu

16

게임에 조금 늦었지만 여기에 임의의 함수를 사용하여 pandas Series, DataFrame 및 다중 인덱스 DataFrame 개체를 정렬하는 함수를 만드는 방법이 있습니다.

df.iloc[index]위치별로 Series / DataFrame의 행을 참조하는 메서드를 사용합니다 ( df.loc값으로 참조 하는와 비교 ). 이를 사용하여 일련의 위치 인수를 반환하는 함수가 있어야합니다.

def sort_pd(key=None,reverse=False,cmp=None):
    def sorter(series):
        series_list = list(series)
        return [series_list.index(i) 
           for i in sorted(series_list,key=key,reverse=reverse,cmp=cmp)]
    return sorter

이를 사용하여 사용자 지정 정렬 기능을 만들 수 있습니다. 이것은 Andy Hayden의 답변에 사용 된 데이터 프레임에서 작동합니다.

df = pd.DataFrame([
    [1, 2, 'March'],
    [5, 6, 'Dec'],
    [3, 4, 'April']], 
  columns=['a','b','m'])

custom_dict = {'March':0, 'April':1, 'Dec':3}
sort_by_custom_dict = sort_pd(key=custom_dict.get)

In [6]: df.iloc[sort_by_custom_dict(df['m'])]
Out[6]:
   a  b  m
0  1  2  March
2  3  4  April
1  5  6  Dec

이것은 다중 인덱스 DataFrames 및 Series 객체에서도 작동합니다.

months = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec']

df = pd.DataFrame([
    ['New York','Mar',12714],
    ['New York','Apr',89238],
    ['Atlanta','Jan',8161],
    ['Atlanta','Sep',5885],
  ],columns=['location','month','sales']).set_index(['location','month'])

sort_by_month = sort_pd(key=months.index)

In [10]: df.iloc[sort_by_month(df.index.get_level_values('month'))]
Out[10]:
                 sales
location  month  
Atlanta   Jan    8161
New York  Mar    12714
          Apr    89238
Atlanta   Sep    5885

sort_by_last_digit = sort_pd(key=lambda x: x%10)

In [12]: pd.Series(list(df['sales'])).iloc[sort_by_last_digit(df['sales'])]
Out[12]:
2    8161
0   12714
3    5885
1   89238

나에게 이것은 깨끗하게 느껴지지만 최적화 된 팬더 작업에 의존하는 대신 파이썬 작업을 많이 사용합니다. 스트레스 테스트를 한 적은 없지만 매우 큰 DataFrame에서 느려질 수 있다고 생각합니다. 성능이 열 추가, 정렬 및 삭제와 어떻게 비교되는지 확실하지 않습니다. 코드 속도를 높이는 방법에 대한 조언을 주시면 감사하겠습니다!


여러 열 / 인덱스를 정렬하는 데이 방법이 적용됩니까?
ConanG

예, 그러나 선택한 답변이이를 수행하는 훨씬 더 나은 방법입니다. 인덱스가 여러 개인 경우 원하는 정렬 순서에 따라 정렬 한 다음 df.sort_index()모든 인덱스 수준을 정렬 하는 데 사용하십시오 .
Michael Delgado

9
import pandas as pd
custom_dict = {'March':0,'April':1,'Dec':3}

df = pd.DataFrame(...) # with columns April, March, Dec (probably alphabetically)

df = pd.DataFrame(df, columns=sorted(custom_dict, key=custom_dict.get))

March, April, Dec 열이있는 DataFrame을 반환합니다.


이것은 열의 사용자 지정 조건자를 기반으로 행을 정렬하는 대신 실제 열을 정렬합니까?
cs95
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.