IT TIP

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

itqueen 2020. 11. 30. 20:29
반응형

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


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

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

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

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("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()

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})

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


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을 반환합니다.


게임에 조금 늦었지만 임의의 함수를 사용하여 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

To me this feels clean, but it uses python operations heavily rather than relying on optimized pandas operations. I haven't done any stress testing but I'd imagine this could get slow on very large DataFrames. Not sure how the performance compares to adding, sorting, then deleting a column. Any tips on speeding up the code would be appreciated!


v0.23+ Answer - sort is deprecated.
...But that's not the point of this answer. There are multiple options to do this.

One simple method is using the output Series.map and Series.argsort to index into df using DataFrame.iloc (since argsort produces sorted integer positions); since you have a dictionary; this becomes easy.

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

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


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

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

If you need to sort in descending order, invert the mapping.

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

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

Note that this only works on numeric items. Otherwise, you will need to workaround this using sort_values, and accessing the index:

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

More options are available with astype (this is deprecated now), or pd.Categorical, but you need to specify ordered=True for it to work correctly.

# 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
)

Now, a simple sort_values call will do the trick:

df.sort_values('m')

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

The categorical ordering will also be honoured when groupby sorts the output.

참고URL : https://stackoverflow.com/questions/13838405/custom-sorting-in-pandas-dataframe

반응형