이번 포스팅에서는 Python pandas DataFrame의 칼럼 이름 바꾸는 방법(how to change column name in python pandas DataFrame), index 이름을 바꾸는 방법(how to change index name in python pandas DataFrame)을 소개하겠습니다. 


(1) pandas DataFrame의 칼럼 이름 바꾸기

    :  df.columns = ['a', 'b']

    :  df.rename(columns = {'old_nm' : 'new_nm'), inplace = True)

(2) pandas DataFrame의 인덱스 이름 바꾸기

    : df.index = ['a', 'b']

    : df.rename(index = {'old_nm': 'new_nm'), inplace = True)




  (1) Python pandas DataFrame 의 칼럼 이름 바꾸기


예제로 사용할 간단한 pandas DataFrame을 만들어보겠습니다. 


In [1]: import pandas as pd


In [2]: df = pd.DataFrame({'id': ['a', 'b', 'c', 'd'],

   ...: 'col_1': [1, 2, 3, 4],

   ...: 'col_2': [1, 1, 2, 2]},

   ...: columns = ['id', 'col_1', 'col_2'])


In [3]: df

Out[3]:

  id  col_1  col_2

0  a      1      1

1  b      2      1

2  c      3      2

3  d      4      2


In [4]: df.columns

Out[4]: Index(['id', 'col_1', 'col_2'], dtype='object')





(1-1) df.columns = ["new_1", "new_2"] 를 이용한 칼럼 이름 바꾸기


In [5]: df.columns = ["group", "val_1", "val_2"]


In [6]: df

Out[6]:

  group  val_1  val_2

0     a      1      1

1     b      2      1

2     c      3      2

3     d      4      2



df.columns 메소드를 사용해서 칼럼 이름을 변경하고자 하는 경우, DataFrame의 칼럼 개수 (number of columns in DataFrame)를 정확하게 일치시켜주어야 합니다. DataFrame의 칼럼 개수와 df.columns = [xx, xx, ...] 의 칼럼 개수가 서로 다를 경우 ValueError: Length mismatch 에러가 발생합니다. 


# need to match the number of columns

# ValueError: Length mismatch


In [7]: df.columns = ["group", "val_1"] # length mismatch error

   ...:

Traceback (most recent call last):


File "<ipython-input-7-5ab3ecd42fe8>", line 1, in <module>

df.columns = ["group", "val_1"]

... 중간 생략 ...


File "C:\Users\admin\Anaconda3\lib\site-packages\pandas\core\internals\managers.py", line 155, in set_axis

'values have {new} elements'.format(old=old_len, new=new_len))


ValueError: Length mismatch: Expected axis has 3 elements, new values have 2 elements




(1-2) df.rename(columns = {"old_1": "new_1", "old_2": "new_2"}, inplace=True) 를 이용하여 칼럼 이름 변경하기


In [8]: df.rename(columns = {"id": "group",

   ...: "col_1": "val_1",

   ...: "col_2": "val_2"}, inplace = True)

   ...:

In [9]: df

Out[9]:

  group  val_1  val_2

0     a      1      1

1     b      2      1

2     c      3      2

3     d      4      2



df.columns 메소드와는 달리 df.rename(columns = {'old': 'new'}) 함수는 DataFrame의 칼럼 개수를 맞추어줄 필요가 없으며, 특정 칼럼 이름만 선별적으로 바꿀 수 있습니다. 아래 예제는 "group" 칼럼 이름을 "ID_2" 라는 새로운 칼럼 이름으로 바꾸어준 예입니다. 


In [10]: df.rename(columns = {"group": "ID_2"}, inplace = True)


In [11]: df

Out[11]:

  ID_2  val_1  val_2

0    a      1      1

1    b      2      1

2    c      3      2

3    d      4      2



lambda 함수를 사용하여서 기존 DataFrame의 칼럼 앞에 "X_" 라는 접두사(prefix)를 붙인 새로운 칼럼 이름을 만들어보겠습니다. 


In [14]: df = pd.DataFrame({'id': ['a', 'b', 'c', 'd'],

    ...: 'col_1': [1, 2, 3, 4],

    ...: 'col_2': [1, 1, 2, 2]},

    ...: columns = ['id', 'col_1', 'col_2'])


In [15]: df

Out[15]:

  id  col_1  col_2

0  a      1      1

1  b      2      1

2  c      3      2

3  d      4      2


In [16]: df.rename(columns = lambda x: "X_" + x, inplace = True)


In [17]: df

Out[17]:

  X_id  X_col_1  X_col_2

0    a        1        1

1    b        2        1

2    c        3        2

3    d        4        2




  (2) DataFrame의 Index 이름 바꾸기


(2-1) df.index = ['new_idx1', 'new_idx2'] 을 이용하여 Index 이름 바꾸기


이때 DataFrame의 index 개수와 바꾸고자 하는 index 이름의 개수를 서로 맞추어주어야 합니다. 


In [17]: df

Out[17]:

  X_id  X_col_1  X_col_2

0    a        1        1

1    b        2        1

2    c        3        2

3    d        4        2


In [18]: df.index

Out[18]: RangeIndex(start=0, stop=4, step=1)


In [19]: df.index = ['a', 'b', 'c', 'd']


In [20]: df

Out[20]:

  X_id  X_col_1  X_col_2

a    a        1        1

b    b        2        1

c    c        3        2

d    d        4        2



(2-2) df.rename(index = {'old_idx': 'new_idx'}, inplace = True) 를 이용한 index 이름 바꾸기


In [21]: df.rename(index = {0: 'a',

    ...: 1: 'b',

    ...: 2: 'c',

    ...: 3: 'd'}, inplace = True)


In [22]: df

Out[22]:

  X_id  X_col_1  X_col_2

a    a        1        1

b    b        2        1

c    c        3        2

d    d        4        2



많은 도움이 되었기를 바랍니다. 

이번 포스팅이 도움이 되었다면 아래의 '공감~'를 꾹 눌러주세요. :-)

Posted by R Friend R_Friend

지난번 포스팅에서는 Python pandas의 pd.read_excel() 함수를 사용하여 외부의 Excel 파일을 읽어와서 pandas DataFrame으로 만드는 방법(https://rfriend.tistory.com/464)을 소개하였습니다. 


이번 포스팅에서는 반대로 Python pandas의 to_excel() 메소드를 사용하여 pandas DataFrame을 Excel 파일에 내보내서 쓰는 방법을 소개하겠습니다. 


(1) 하나의 DataFrame을 하나의 Excel Sheet에 쓰기

(2) 두 개 이상의 DataFrame을 여러개의 Excel Sheets에 나누어서 쓰기



 (1) 하나의 DataFrame을 하나의 Excel Sheet에 쓰기


먼저 필요한 라이브러리를 불러오고 Excel 파일로 저장할 경로와 파일 이름을 설정하겠습니다.


In [1]: import numpy as np

   ...: import pandas as pd

   ...: import os


In [2]: base_dir = "C:/Users/admin/Documents/data"

   ...: file_nm = "df.xlsx"

   ...: xlxs_dir = os.path.join(base_dir, file_nm) 



다음으로 예제로 사용할 DataFrame을 만들어보겠습니다. 


In [3]: df = pd.DataFrame({'group': ['a', 'b', 'c', 'd', 'e'],

   ...: 'value_1': [10.056, 20.534, 30.90, 41.9423, 35.21],

   ...: 'value_2': [200, 500, 600, np.nan, 1200]},

   ...: index = [1, 2, 3, 4, 5])


In [4]: df

Out[4]:

  group  value_1  value_2

1     a  10.0560    200.0

2     b  20.5340    500.0

3     c  30.9000    600.0

4     d  41.9423      NaN

5     e  35.2100   1200.0



이제 준비가 되었으니 'df'라는 이름의 DataFrame을 'df.xlxs' 라는 이름의 Excel 파일로 내보내기 (쓰기)를 to_excel() 메소드를 사용하여 해보겠습니다. 


#-- write an object to an Excel sheet using pd.DataFrame.to_excel()

df.to_excel(xlxs_dir, # directory and file name to write

            sheet_name = 'Sheet1', 

            na_rep = 'NaN', 

            float_format = "%.2f", 

            header = True, 

            #columns = ["group", "value_1", "value_2"], # if header is False

            index = True, 

            index_label = "id", 

            startrow = 1, 

            startcol = 1, 

            #engine = 'xlsxwriter', 

            freeze_panes = (2, 0)

            ) 



위의 df.to_excel() 을 실행시켰더니 아래와 같이 'df.xlsx' 라는 이름의 Excel ('C:/Users/admin/Documents/data\\df.xlsx')에 'Sheet1' 의 sheet (sheet_name = 'Sheet1')에 df DataFrame이 잘 쓰여졌음을 확인할 수 있습니다. 




'value_1' 칼럼은 부동소수형의 숫자가 들어있는데요, 자리수가 소수점 2자리 (float_format = "%.2f") 까지 반올림 되어서 보기에 좋게 제시가 되었습니다. 


'value_2' 칼럼에 결측값이 포함되어 있는데요, 엑셀에는 'NaN'으로 표기(na_rep = 'NaN')가 되어있습니다. 


열 이름은 DataFrame의 칼럼 이름(header = True)을 그대로 가져와서 사용하였으며, DataFrame의 index를 'id'라는 이름의 칼럼(index = True, index_label = "id")으로 내보냈습니다. 


엑셀에 DataFrame을 쓸 때 처음 시작하는 행과 열의 위치를 2행, 2열로 지정(startrow = 1, startcol = 1)하였습니다. 


그리고, 2행을 기준으로 틀 고정(freeze_panes = (2, 0))을 시켰습니다. 




 (2) 두 개 이상의 DataFrame을 여러개의 Excel Sheets에 나누어서 쓰기


예제로 사용할 두 개의 Python pandas DataFrame을 만들어보겠습니다. 


In [8]: df_1 = df.copy()


In [9]: df_2 = pd.DataFrame(np.arange(15).reshape(5, 3),

   ...: columns = ['col_1', 'col_2', 'col_3'],

   ...: index = [1, 2, 3, 4, 5])


In [10]: df_1

Out[10]:

  group  value_1  value_2

1     a  10.0560    200.0

2     b  20.5340    500.0

3     c  30.9000    600.0

4     d  41.9423      NaN

5     e  35.2100   1200.0


In [11]: df_2

Out[11]:

   col_1  col_2  col_3

1      0      1      2

2      3      4      5

3      6      7      8

4      9     10     11

5     12     13     14



이제 'df_1'과 'df_2' 라는 이름의 2개의 DataFrame을 (1)번과 똑같은 경로의, 똑같은 파일 이름('C:/Users/admin/Documents/data\\df.xlsx') 으로 내보내서 써보겠습니다. 이렇게 동일한 파일 경로/이름을 사용하면 기존의 엑셀 파일을 덮어쓰기(overwirte) 해버리므로 기존 파일의 내용은 지워져버립니다 (주의 요망). 


2개 이상의 DataFrame을 하나의 엑셀 파일에 여러개의 Sheets 로 나누어서 쓰려면 먼저 pd.ExcelWriter() 객체를 지정한 후에, sheet_name 을 나누어서 지정하여 써주어야 합니다. 


# Write two DataFrames to Excel using to_excel(). Need to specify an ExcelWriter object first.

with pd.ExcelWriter(xlxs_dir) as writer:

    df_1.to_excel(writer, sheet_name = 'DF_1')

    df_2.to_excel(writer, sheet_name = 'DF_2') 



'DF_1'과 'DF_2' 라는 이름의 Sheets 로 나누어서 2개의 DataFrame이 잘 쓰여졌음을 알 수 있습니다. 






만약 같은 경로/이름의 Excel 파일이 열려있는 상태에서 df.to_excel() 을 실행하게 되면 "PermissionError: [Errno 13] Permission denied:" 에러가 발생합니다. 이때는 열려있는 Excel 파일을 닫고 df.to_excel() 을 다시 실행하던가 (덮어쓰기를 해도 괜찮다는 가정하에), 아니면 저장할 Excel 파일의 경로/이름을 바꾸어주기 바랍니다. 


In [13]: with pd.ExcelWriter(xlxs_dir) as writer:

    ...: df_1.to_excel(writer, sheet_name = 'DF_1')

    ...: df_2.to_excel(writer, sheet_name = 'DF_2')

    ...:

    ...:

Traceback (most recent call last):


File "<ipython-input-13-9ba7e09cf9e3>", line 3, in <module>

df_2.to_excel(writer, sheet_name = 'DF_2')


File "C:\Users\admin\Anaconda3\lib\site-packages\pandas\io\excel.py", line 1191, in __exit__

self.close()


File "C:\Users\admin\Anaconda3\lib\site-packages\pandas\io\excel.py", line 1195, in close

return self.save()


 .... 중간 생략 ....


File "C:\Users\admin\Anaconda3\lib\site-packages\xlsxwriter\workbook.py", line 611, in _store_workbook

allowZip64=self.allow_zip64)


File "C:\Users\admin\Anaconda3\lib\zipfile.py", line 1009, in __init__

self.fp = io.open(file, filemode)


PermissionError: [Errno 13] Permission denied: 'C:/Users/admin/Documents/data\\df.xlsx' 



많은 도움이 되었기를 바랍니다. 

이번 포스팅이 도움이 되었다면 아래의 '공감~'를 꾹 눌러주세요. :-)



Posted by R Friend R_Friend

이번 포스팅에서는 Python pandas의 read_excel() 함수를 사용하여 '엑셀 쉬트 데이터셋 (Excel sheet dataset)을 읽어와서 pandas DataFrame으로 만드는 방법'을 소개하겠습니다. 


아래의 첨부 파일은 예제로 사용할 'sales_per_region.xlsx. 라는 이름의 Excel file 입니다. 

sales_per_region.xlsx


위의 엑셀 자료를 읽어와서 Python pandas의 DataFrame으로 만들 때 아래의 요건을 충족시키고자 합니다. 

(1) 엑셀 자료로 부터 읽어올 데이터셋은 'Sheet1' 이름의 첫번째 쉬트에 있으며, 3행 A열 부터 ~ 10행 D열까지의 Cell에 있는 데이터입니다.  (sheet_name = 'Sheet1', header = 2)

(2) '3행은 칼럼 이름(header)'이며, 'A열의 'id' 칼럼은 index로 사용'하고자 합니다. (header = 2, index_col='id')

(3) 'region' 칼럼은 문자열(string), 'sales_representative' 칼럼은 정수형(integer), 'sales_amount' 칼럼은 부동소수형(float)의 데이터 형태(data type)입니다. (dtype = {'region': str, 'sales_representative': np.int64, 'sales_amount': float})

(4) pandas DataFrame으로 불러왔을 때 'sales_amount' 칼럼에 천 단위 구분 기호 콤마(',')는 없애고 싶습니다. (thousands = ',')

(5) 총 읽어올 행의 개수(number of rows)는 10개로 한정하고 싶습니다. (nrows=10)

(6) 11번째 행에 '# ignore this line' 처럼 '#' (comment character) 으로 시작하면 그 뒤의 행 전체는 무시하고자 합니다. (comment = '#')



# import libraries

 import numpy as np

 import pandas as pd

 import os


# set directory with yours

 base_dir = 'D:/admin/Documents'

 excel_file = 'sales_per_region.xlsx'

 excel_dir = os.path.join(base_dir, excel_file)


# read a excel file and make it as a DataFrame

 df_from_excel = pd.read_excel(excel_dir, # write your directory here

                              sheet_name = 'Sheet1', 

                              header = 2, 

                              #names = ['region', 'sales_representative', 'sales_amount']

                              dtype = {'region': str

                                         'sales_representative': np.int64

                                         'sales_amount': float}, # dictionary type

                              index_col = 'id', 

                              na_values = 'NaN', 

                              thousands = ',', 

                              nrows = 10, 

                              comment = '#')



혹시 엑셀 자료에 칼럼 이름(header)가 없다면 names = ['region', 'sales_representative', 'sales_amount'] 이런식으로 직접 칼럼 이름을 입력해주면 됩니다. 데이터가 있는 행과 열은 pandas가 알아서 찾아서 지정해주며, 데이터 형태(data type)도 일일이 지정해주지 않아도 알아서 추정을 해서 설정을 해줍니다. 


'sales_per_region.xlsx' 엑셀 파일을 'df_from_excel' 이라는 이름의 DataFrame으로 잘 불러왔습니다. 확인차 index, data type, 'region' 칼럼을 조회해보겠습니다. 제대로 잘 불러온거 맞지요?!


# check index

df_from_excel.index

Int64Index([1, 2, 3, 4, 5, 6, 7], dtype='int64', name='id')


# check data type


df_from_excel.dtypes

region                   object
sales_representative      int64
sales_amount            float64
dtype: object


# check 'region' column

df_from_excel['region']

id
1      seoul
2     inchon
3      busan
4    guangju
5      ulsan
6     sejong
7     jeunju
Name: region, dtype: object



많은 도움이 되었기를 바랍니다. 

Python pandas DataFrame을 Excel로 쓰기 (내보내기)를 하는 방법은 https://rfriend.tistory.com/466 를 참고하세요. 

이번 포스팅이 도움이 되었다면 아래의 '공감~'를 꾹 눌러주세요. :-)


Posted by R Friend R_Friend

이번 포스팅에서는 Python pandas DataFrame의 숫자형 변수에서 천 단위 숫자의 자리 구분 기호인 콤마(',')를 없애는 2가지 방법을 소개하겠습니다. 


예제로 사용할 데이터셋은 Wikipedia 에서 찾은 per capita nominal GDP for countries 2018년도 국가별 1인당 소득수준 (단위: US$) 데이터입니다.  아래의 데이터 캡쳐해놓은 그림처럼 1인당 소득수준(US$)의 숫자에 천 단위 자리 구분 기호로 콤마(comma, ',')가 들어있는데요, 이게 웹사이트나 엑셀에서 눈으로 보기에는 가독성이 좋습니다만, 분석을 할 때는 숫자형으로 인식을 하지 않고 문자열로 인식을 한다든지, 콤마(',')를 칼럼 구분자로 잘못 인식을 한다든지 해서 문제를 야기할 수 있습니다. 이에 천 단위 자리수 구분 기호 콤마(',' comma)를 없애는 2가지 방법을 소개하겠습니다. 

(1) pd.read_csv() 에서 thousands = ',' 옵션으로 천 단위 자리수 구분 콤마 없애고 불러오기

(2) DataFrame의 문자열 DataFrame.column.str.replace(',', '').astype('int64') 메소드를 이용하여 변환하기

(3) PostgreSQL, Greenplum DB에서 천 단위 자리수 구분 콤마 없애기


per_capita_GDP_for_countries.txt


 (1) pd.read_csv() 에서 thousands = ',' 옵션 설정하여 
      text, csv file을 불러올 때 천 단위 자리수 구분 없애고 불러오기

원천 데이터를 pd.read_csv() 함수로 불러올 때 천 단위 구분 기호를 신경 안쓰고, 데이터 경로와 구분자(탭, delimiter = '\t') 정도만 설정해주고 불러오면 아래처럼 'USD' 칼럼에 숫자가 천 단위마다 구분 기호 콤마(',')가 포함되어 있습니다. 

In [1]: import pandas as pd

In [2]: import os


In [3]: base_dir = 'D:/admin/Documents/'


In [4]: file_nm = 'per_capita_GDP_for_countries.txt'


In [5]: data_dir = os.path.join(base_dir, file_nm)


In [6]: per_capita_1 = pd.read_csv(data_dir, delimiter = '\t')


In [7]: per_capita_1.head(10)

Out[7]:

   Rank Country/Territory      USD

0     1        Luxembourg  114,234

1     2       Switzerland   82,950

2     2             Macau   82,388

3     3            Norway   81,695

4     4           Ireland   76,099

5     5           Iceland   74,278

6     6             Qatar   70,780

7     7         Singapore   64,041

8     8     United States   62,606

9     9           Denmark   60,692




이번에는 pd.read_csv() 함수에 thousands = ',' 라는 옵션을 추가해서 불어와 보겠습니다. 'USD' 칼럼에 천 단위 자리 구분 기호가 없어졌습니다.  아무래도 나중에 두번일 안하려면 데이터 불러올 때 부터 신경을 쓰는게 좋겠지요?!

In [8]: per_capita_2 = pd.read_csv(data_dir, delimiter = '\t', thousands = ',')


In [9]: per_capita_2.head(10)

Out[9]:

   Rank Country/Territory     USD

0     1        Luxembourg  114234

1     2       Switzerland   82950

2     2             Macau   82388

3     3            Norway   81695

4     4           Ireland   76099

5     5           Iceland   74278

6     6             Qatar   70780

7     7         Singapore   64041

8     8     United States   62606

9     9           Denmark   60692





 (2) DataFrame의 문자열 df.column.str.replace(',', '').astype('int64') 메소드
     이용하여 데이터 형태 및 유형 변환하기

이번에는 '소 잃고 외양간 고치기' 방법이 되겠습니다. -_-;

먼저, 'USD' 칼럼의 천 단위 구분 기호 콤마 ','를 그대로 불러왔던 첫번째의 'per_capita_1' DataFrame의 칼럼별 data type을 살펴보겠습니다. 'USD' 칼럼이 'object'로 되어있습니다. (정수형 integer 가 아닙니다!) 

In [10]: per_capita_1.dtypes

Out[10]:

Rank int64

Country/Territory object

USD object
dtype: object 


이제 문자열(string)의 replace() 메소드를 이용해서 콤마(',')를 비어있는 '' 로 변경(replace)하고, 데이터 형태를 정수형(integer64)로 지정(astype('int64')해보겠습니다. 애초 'USD' 칼럼이 'object' 형태였다면, str.replace(',', '').astype('int64')로 새로 만든 'USD_2' 칼럼은 'int64' 형태로 천 단위 숫자 구분 기호 콤마 없이 잘 들어가 있습니다. 

In [11]: per_capita_1['USD_2'] = per_capita_1.USD.str.replace(',', '').astype('int64')

In [12]: per_capita_1.dtypes

Out[12]:

Rank int64

Country/Territory object

USD object

USD_2 int64

dtype: object


In [13]: per_capita_1.head(10)

Out[13]:

   Rank Country/Territory      USD   USD_2

0     1        Luxembourg  114,234  114234

1     2       Switzerland   82,950   82950

2     2             Macau   82,388   82388

3     3            Norway   81,695   81695

4     4           Ireland   76,099   76099

5     5           Iceland   74,278   74278

6     6             Qatar   70,780   70780

7     7         Singapore   64,041   64041

8     8     United States   62,606   62606

9     9           Denmark   60,692   60692





  (3) PostgreSQL, Greenplum DB 에서 천 단위 구분 기호 콤마(',') 없애는 방법


DB에서도 천 단위 구분 기호 콤마가 골치거리인건 마찬가지이죠. 아래 SQL query 참고하세요. 

 SELECT replace(column_name, ',', '')::numeric

 FROM table_name


많은 도움이 되었기를 바랍니다. 

이번 포스팅이 도움이 되었다면 아래의 '공감~'를 꾹 눌러주세요. :-)


Posted by R Friend R_Friend

이번 포스팅에서는 Python pandas의 DataFrame, Series 에서 특정 변수를 기준으로 순서를 구할 때 사용하는 rank() 함수를 소개하겠습니다. 

순위(Rank)는 정렬(Sort)와 밀접한 관련이 있는데요, 참고로 Python에서 자료형별 정렬(Sort) 방법은 아래 링크를 참고하세요. 


  (1) 다양한 동점 처리방법(tie-breaking methods)에 따른 순위(rank) 구하기 비교

순위(rank)를 구할 때 기준 변수의 점수(score)가 동일(tie)한 관측치를 어떻게 처리하는지에 따라서 5가지 방법이 있습니다. 

[ 순위 구할 때 동점 처리하는 5가지 방법 ]

  • 평균(method='average') : 동점 관측치 간의 그룹 내 평균 순위 부여 (default 설정)
  • 최소값(method='min') : 동점 관측치 그룹 내 최소 순위 부여
  • 최대값(method='max') : 동점 관측치 그룹 내 최대 순위 부여
  • 첫번째 값 (method='first') : 동점 관측치 중에서 데이터 상에서 먼저 나타나는 관측치부터 순위 부여
  • 조밀하게 (method='dense') : 최소값('min')과 같은 방법으로 순위부여하나, 'min'과는 다르게 그룹 간 순위가 '1'씩 증가함 (like ‘min’, but rank always increases by 1 between groups)


동점을 포함하고 있는 간단한 예제 DataFrame을 만들어보겠습니다. 

In [1]: import numpy as np


In [2]: import pandas as pd


In [3]: df = pd.DataFrame({

   ...: 'name': ['kim', 'lee', 'park', 'choi', 'jung', 'gang', 'nam'],

   ...: 'score': [70, 95, 100, 95, 70, 90, 70]

   ...: }, columns=['name', 'score'])


In [4]: df

Out[4]:

name score

0 kim 70

1 lee 95

2 park 100

3 choi 95

4 jung 70

5 gang 90

6 nam 70


이제 순위 구할 때 동점을 처리하는 5가지 방법별로 순위 결과가 어떻게 다른지 확인해보겠습니다. (예제를 시험점수로 가정하고, 점수가 높을 수록 상위 순위가 나오도록 함. ascending = False)

In [5]: df['rank_by_average'] = df['score'].rank(ascending=False) # rank default method='average

In [6]: df['rank_by_min'] = df['score'].rank(method='min', ascending=False)


In [7]: df['rank_by_max'] = df['score'].rank(method='max', ascending=False)


In [8]: df['rank_by_first'] = df['score'].rank(method='first', ascending=False)


In [9]: df['rank_by_dense'] = df['score'].rank(method='dense', ascending=False)


In [10]: df

Out[10]:

  name   score   rank_by_average    rank_by_min   rank_by_max    rank_by_first \

0 kim        70                   6.0              5.0              7.0              5.0

1 lee         95                   2.5              2.0              3.0              2.0

2 park      100                  1.0               1.0              1.0              1.0

3 choi        95                  2.5               2.0              3.0              3.0

4 jung        70                  6.0               5.0              7.0              6.0

5 gang       90                  4.0               4.0              4.0              4.0

6 nam        70                  6.0               5.0              7.0              7.0


rank_by_dense

0            4.0

1            2.0

2            1.0

3            2.0

4            4.0

5            3.0

6            4.0



  (2) 순위를 오름차순으로 구하기 (Rank in Ascending order)

rank(ascending = True) 으로 설정해주면 오름차순 (제일 작은 점수가 순위 '1'이고, 점수가 높아질수록 하나씩 순위 증가)으로 순위를 구합니다. Default 설정이 ascending=True 이므로 별도로 설정을 안해줘도 자동으로 오름차순 순위가 구해집니다. 

In [11]: df_score = df[['name', 'score']].copy()


In [12]: df_score['rank_ascending'] = df_score['score'].rank(method='min', ascending=True)


In [13]: df_score

Out[13]:

name    score     rank_ascending

0 kim        70                  1.0

1 lee         95                    5.0

2 park      100                    7.0

3 choi        95                    5.0

4 jung        70                    1.0

5 gang       90                    4.0

6 nam        70                    1.0 



  (3) 그룹 별로 순위 구하기 (Rank by Groups): df.groupby().rank()

Groupby operator를 사용하면 그룹별로 따로 따로 순위를 구할 수 있습니다. 

In [14]: from itertools import chain, repeat

    ...:


In [15]: df2 = pd.DataFrame({

    ...: 'name': ['kim', 'lee', 'park', 'choi']*3,

    ...: 'course': list(chain.from_iterable((repeat(course, 4)

    ...: for course in ['korean', 'english', 'math']))),

    ...: 'score': [70, 95, 100, 95, 65, 80, 95, 90, 100, 85, 90, 90]

    ...: }, columns=['name', 'course', 'score'])


In [16]: df2

Out[16]:

    name   course  score

0    kim   korean     70

1    lee   korean     95

2   park   korean    100

3   choi   korean     95

4    kim  english     65

5    lee  english     80

6   park  english     95

7   choi  english     90

8    kim     math    100

9    lee     math     85

10  park     math     90

11  choi     math     90


In [17]: df2['rank_by_min_per_course'] = df2.groupby('course')['score'].rank(method='min', ascending=False)


In [18]: df2

Out[18]:

    name   course  score  rank_by_min_per_course

0    kim   korean     70                     4.0

1    lee   korean      95                     2.0

2   park   korean    100                     1.0

3   choi   korean      95                     2.0

4    kim  english      65                     4.0

5    lee  english       80                     3.0

6   park  english      95                     1.0

7   choi  english      90                     2.0

8    kim     math    100                     1.0

9    lee     math      85                     4.0

10  park     math     90                     2.0

11  choi     math     90                     2.0



  (4) 칼럼을 기준으로 순위 구하기 (Rank over the columns): df.rank(axis=1)

위의 (1), (2), (3) 번의 예시는 전부 행을 기준(위/아래 방향)으로 한 순위(rank over the rows) 였습니다. 필요에 따라서는 열을 기준(왼쪽/오른쪽 방향)으로 한 순위(rank over the columns)을 해야할 때도 있을텐데요, rank(axis=1) 을 설정해주면 열 기준 순위를 구할 수 있습니다. 

In [19]: df3 = pd.DataFrame({

    ...: 'col_1': [1, 2, 3, 4],

    ...: 'col_2': [3, 5, 1, 2],

    ...: 'col_3': [3, 1, 2, 4]})


In [20]: df3

Out[20]:

 col_1 col_2 col_3

0   1      3      3

1   2      5      1

2   3      1      2

3   4      2      4


In [21]: df3.rank(method='min', ascending=False, axis=1)

Out[21]:

   col_1    col_2    col_3

0    3.0       1.0       1.0

1    2.0       1.0       3.0

2    1.0       3.0       2.0

3    1.0       3.0       1.0 


많은 도움이 되었기를 바랍니다. 

이번 포스팅이 도움이 되었다면 아래의 '공감~'를 꾹 눌러주세요. :-)


Posted by R Friend R_Friend

이번 포스팅에서는 Python pandas의 DataFrame, Series 에서 특정 칼럼 내에 특정 값을 가지고 있는 행 전체를 indexing 해오는 방법 2가지를 소개하겠습니다. 

(1) df.isin() 메소드를 이용한 DataFrame, Series 값 indexing 방법

(2) 비교 조건문 boolean 을 이용한 DataFrame, Series 값 indexing 방법

먼저 간단한 예제로 사용할 DataFrame을 만들어보겠습니다. 

In [1]: import pandas as pd


In [2]: df = pd.DataFrame({'id': ['a', 'b', 'c', 'd', 'e', 'f'],

   ...: 'var': [1, 2, 3, 4, 5, 6]})


In [3]: df

Out[3]:

id var

0 a 1

1 b 2

2 c 3

3 d 4

4 e 5

5 f 6



 (1) df.isin() 메소드를 이용한 DataFrame, Series 값 indexing 방법

pandas DataFrame이나 Series에 isin() 메소드를 사용하면 isin() 메소드 안의 값이 들어 있으면, 즉 소속이 되어 있으면 (membership) True를, 들어있지 않으면 False 를 반환합니다. 

In [4]: df['id'].isin(['b', 'e', 'k'])

Out[4]:

0 False

1 True

2 False

3 False

4 True

5 False

Name: id, dtype: bool 


이처럼 조건 값의 소속 여부를 Boolean 값으로 반환해주는 점을 이용하여, 특정 값이 들어있는 행을 DataFrame, Series에서 indexing 해올 수 있습니다.  위의 예제 'df' DataFrame의 'id' 칼럼에서 'b', 'e', 'k' 값이 들어있는 행 전체를 가져와 보겠습니다. 

In [5]: df[df['id'].isin(['b', 'e', 'k'])]

Out[5]:

id var

1 b  2
4 e  5 


만약 'id'라는 칼럼 혹은 'var'라는 칼럼 중에서 특정 값이 어느 한군데라도(OR) 소속이 되어있으면 행을 가져와 보겠습니다. 

In [6]: df[df['id'].isin(['b', 'e', 'k']) | df['var'].isin([1, 8])]

   ...:

Out[6]:

id var

0 a 1

1 b 2
4 e 5 



 (2) 비교 조건문 boolean 을 이용한 DataFrame, Series 값 indexing 방법

위의 isin() 메소드를 이용한 [6]번째 실행 셀의 결과와 동일한 값을 indexing 해오는 것을, 이번에는 조건문 boolean 을 이용해서 해보겠습니다. 아무래도 위의 [6]번 isin() 메소드를 썼을 때보다 '|'(OR)를 모든 비교 조건문을 연결하다 보니 코드가 더 길고 복잡합니다. 

따라서, 특정 값이 포함/ 소속 (Membership) 여부를 조건으로 해서 DataFrame, Series로부터 행 전체를 indexing해와야 하는 경우 isin() 메소드를 유용하게 사용할 수 있습니다. (물론 아래의 비교 조건문의 경우 단지 포함/소속 여부 많이 아닌 모든 조건문에 범용적으로 사용할 수 있는 장점이 있습니다.)

In [7]: df[(df['id'] == 'b') | (df['id'] == 'e') | (df['id'] == 'k') | (df['var'] == 1) | (df['var'] == 8)]

Out[7]:

id var

0 a 1

1 b 2
4 e 5



 TypeError: cannot compare a dtyped [object] array with a scalar of type [bool] 

참고로, 여러개의 비교 조건문을 & (AND), 또는 | (OR) 로 연결해서 다수개의 조건을 AND, 또는 OR로 만족하는 행을 가져오고 싶을 경우 반드시 조건문에 (조건문) & (조건문), (조건문) | (조건문) 처럼 조건문에 괄호 ( ) 를 꼭 쳐줘야 합니다. (Be sure to include the parentheses in the conditions)

In [8]: df[df['id'] == 'b' | df['id'] == 'e' | df['id'] == 'k']

Traceback (most recent call last):


File "<ipython-input-8-3140416d729c>", line 1, in <module>

df[df['id'] == 'b' | df['id'] == 'e' | df['id'] == 'k']


File "C:\Users\admin\Anaconda3\lib\site-packages\pandas\core\ops.py", line 836, in wrapper

na_op(self.values, other),


File "C:\Users\admin\Anaconda3\lib\site-packages\pandas\core\ops.py", line 807, in na_op

x.dtype, type(y).__name__))


TypeError: cannot compare a dtyped [object] array with a scalar of type [bool]


Traceback (most recent call last):


File "<ipython-input-8-3140416d729c>", line 1, in <module>

df[df['id'] == 'b' | df['id'] == 'e' | df['id'] == 'k']


File "C:\Users\admin\Anaconda3\lib\site-packages\pandas\core\ops.py", line 836, in wrapper

na_op(self.values, other),


File "C:\Users\admin\Anaconda3\lib\site-packages\pandas\core\ops.py", line 807, in na_op

x.dtype, type(y).__name__))


TypeError: cannot compare a dtyped [object] array with a scalar of type [bool]


TypeError가 안나게 제대로 조건문 boolean indexing을 하려면 아래처럼 비교 조건문별로 '(비교 조건문) | (비교 조건문) 처럼 괄호 ( ) 를 쳐주면 됩니다. 

In [9]: df[ (df['id'] == 'b') | (df['id'] == 'e') | (df['id'] == 'k')]

Out[9]:

id var

1 b 2
4 e 5 


많은 도움이 되었기를 바랍니다. 

이번 포스팅이 도움이 되었다면 아래의 '공감~'를 꾹 눌러주세요. :-)

Posted by R Friend R_Friend

이번 포스팅에서는 빠르고 메모리를 효율적으로 사용해서 반복자((fast and memory-efficient iterator)를 만들어주는 itertools 모듈을 사용해서 리스트 원소를 n번 반복하고 묶어서 새로운 리스트를 만드는 4가지 유형의 방법을 소개하겠습니다. 


먼저 itertools 모듈에서 chain(), repeat() 함수를 불러오고, 예제로 사용할 반복할 리스트(numbers)와 반복할 회수(n)을 만들어놓겠습니다. 

 In [1]: from itertools import chain, repeat

In [2]: numbers = [1, 2, 3]


In [3]: n = 3


  (1) itertools.repeat(object, times) : object를 times 만큼 반복하기


itertools의 repeat() 함수로 [1, 2, 3] 리스트를 3번 반복하면, 아래처럼 리스트 안에 [1, 2, 3] 리스트가 각 각 분리([1, 2, 3], [1, 2, 3], [1, 2, 3])되어서 들어가 있습니다. 

 

In [4]: list(repeat(numbers, n))

Out[4]: [[1, 2, 3], [1, 2, 3], [1, 2, 3]]




  (2) itertools.chain.from_iterable(repeat(object, times))) 
      : times 만큼 "object 전체"를 반복한 연속된 서열을 하나의 서열로 묶어줌


위의 (1)번과는 다르게, [1, 2, 3, 1, 2, 3, 1, 2, 3] 의 단 하나의 리스트로 묶였습니다. 


In [5]: list(chain.from_iterable(repeat(numbers, n)))

Out[5]: [1, 2, 3, 1, 2, 3, 1, 2, 3]

 



  (3) itertools.chain.from_iterable((repeat(object, times) for object in objects)))
       : "objects 내 각 원소"를 times만큼 반복한 연속된 서열을 하나의 서열로 묶어줌

list comprehension 으로 for loop을 이용하여서 numbers 리스트 안의 각 원소인 1, 2, 3 별로 3번씩 반복한 후, 이를 하나의 리스트로 묶어준 경우입니다. 


In [6]: list(chain.from_iterable((repeat(number, n) for number in numbers)))

Out[6]: [1, 1, 1, 2, 2, 2, 3, 3, 3]

 



  (4) itertools.chain.from_iterable((repeat(object, time)
                                              for (object, time) in zip(objects, times))))

  : objects 내 각 원소 다른 수의 times 만큼 반복한 연속된 서열을 하나의 서열로 묶어줌

반복할 수 times 인자를 반복할 대상 objects 내 원소별로 다르게 하고 싶을 때가 있습니다. 이럴 때는 zip() 으로 반복할 대상 object와 반복할 회수 time을 짝으로 묶어서 반복을 시켜주면 됩니다. 


In [7]: numbers = [1, 2, 3]

   ...: n_list = [3, 5, 7]


In [8]: list(chain.from_iterable((repeat(number, n) for (number, n) in zip(numbers, n_list))))

Out[8]: [1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3] 



많은 도움이 되었기를 바랍니다. 

이번 포스팅이 도움이 되었다면 아래의 '공감~'를 꾸욱 눌러주세요. :-)


Posted by R Friend R_Friend

이번 포스팅에서는 Python pandas DataFrame의 index를 reset_index() 하여 칼럼으로 가져오고, 이렇게 가져온 index에 새로운 이름을 부여하는 3가지 방법을 소개하겠습니다. 





먼저, 예제로 사용할 간단한 DataFrame을 만들어보겠습니다. 



import numpy as np

import pandas as pd


df = pd.DataFrame(np.arange(10).reshape(5, 2), 

                 columns=['x1', 'x2'], 

                 index=['a', 'b', 'c', 'd', 'e'])


df


x1x2
a01
b23
c45
d67
e89

 




이제 index 를 칼럼으로 가져오고, 가져온 index의 이름으로 'id'라는 이름을 부여하는 3가지 방법을 차례대로 소개하겠습니다. 


  (1) reset_index() 한 후에 rename()으로 새로운 이름 부여하기



# (1) reset_index() and rename

df.reset_index().rename(columns={"index": "id"})

 

idx1x2
0a01
1b23
2c45
3d67
4e89





  (2) rename_axis() 로 index의 이름을 먼저 바꾸고, 이후에 reset_index() 하기



# (2) rename_axis() first, reset_index() second

df_1 = df.rename_axis('id').reset_index()

df_1

 

idx1x2
0a01
1b23
2c45
3d67
4e89





  (3) df.index.name 으로 index에 이름 할당하고, 다음으로 reset_index() 하기



# (3) assing index name and reset_index()

df.index.name = 'id'

df_2 = df.reset_index()

df_2

 

idx1x2
0a01
1b23
2c45
3d67
4e89



많은 도움이 되었기를 바랍니다. 



Posted by R Friend R_Friend

이번 포스팅에서는 Python pandas의 DataFrame을 


(1) 특정 칼럼을 기준으로 행을 정렬한 후에 (sort DataFrame by value in ascending/descending order)

==> (2) 각 그룹별로 상위 N개 행을 가져오기 (select top N rows by group)


을 하는 방법을 소개하겠습니다. 





먼저 'a'와 'b' 두 개의 그룹별로 5개의 값을 가진 간단한 예제 DataFrame을 만들어보겠습니다. 



import numpy as np

import pandas as pd


# make a sample DataFrame

df = pd.DataFrame({'grp': ["a", "a", "a", "a", "a", "b", "b", "b", "b", "b"], 

                           'val': np.random.uniform(0, 10, 10)})


df


grpval
0a0.275704
1a5.334576
2a5.386807
3a6.033636
4a2.140798
5b2.089792
6b6.396985
7b3.088498
8b5.895689
9b1.157073

 




이제 "val" 변수를 기준으로 내림차순 정렬(sort by 'val' in descending order) 한 후에, 'grp' 칼럼의 'a', 'b' 그룹별로 상위 3개의 값을 가져와서 새로운 데이터프레임을 만들어보겠습니다. 



# sort by value in descending order per group, and select top 3 values per group

df_sort_group_top3 = df.sort_values(by="val", ascending=False).groupby("grp").head(3)


df_sort_group_top3


grpval
6b6.396985
3a6.033636
8b5.895689
2a5.386807
1a5.334576
7b3.088498

 



위의 df_sort_group_top3 결과를 좀더 보기에 좋도록 'a', 'b' 그룹 순서대로, 각 그룹 내에서는 내림차순으로 정렬해보겠습니다. 



df_sort_group_top3.sort_values(by=["grp", "val"], ascending=[True, False])


grpval
3a6.033636
2a5.386807
1a5.334576
6b6.396985
8b5.895689
7b3.088498

 



많은 도움이 되었기를 바랍니다.  

Posted by R Friend R_Friend

이번 포스팅에서는 Python pandas의 pivot_table() 함수를 사용할 때 


- (1) 'DataError: No numeric types to aggregate' 에러가 왜 생기는지

- (2) 'DataError: No numeric types to aggregate' 에러 대응방법은 무엇인지에 대해서 알아보겠습니다. 



먼저 예제로 사용할 간단한 DataFrame을 만들어보겠습니다. 



In [1]: import numpy as np

   ...: import pandas as pd


In [2]: df = pd.DataFrame({'id': [1, 1, 2, 2, 3, 3], 

   ...:                    'col': ['x1', 'x2', 'x1', 'x2', 'x1', 'x2'], 

   ...:                    'sum': [30, 10, 70, 40, 20, 80], 

   ...:                    'name': ['a', 'a', 'b', 'b', 'c', 'c']})

   ...: 

   ...: df

Out[2]: 

  col  id name  sum

0  x1   1    a   30

1  x2   1    a   10

2  x1   2    b   70

3  x2   2    b   40

4  x1   3    c   20

5  x2   3    c   80

 



이제 pandas의 pivot_table() 함수를 이용해서 'id'변수를 index로, 'col' 변수를 열(column)로 하여 'sum'이라는 숫자형 데이터 값(values)을 재구조화(pivot) 해보겠습니다.  pivot_table() 함수의 집계함수(aggregation function)의 디폴트 설정은 평균(aggfunc='mean')으로 되어 있습니다. 아래 코드는 문제 없이 잘 수행이 되었습니다. 



In [3]: df.pivot_table(index = 'id', columns='col', values=['sum'])

Out[3]: 

    sum    

col  x1  x2

id         

1    30  10

2    70  40

3    20  80


In [4]: df.pivot_table(index = 'id', columns='col', values=['sum'], aggfunc='mean')

   ...: 

Out[4]: 

    sum    

col  x1  x2

id         

1    30  10

2    70  40

3    20  80

 



 

 (1) 'DataError: No numeric types to aggregate' 에러가 왜 생기는가?


이번에는 'id' 변수를 index로, 'col'변수를 열(column)변수로 하는 것은 위와 동일하나, 재구조화하는 테이블의 값(value)으로 숫자형(nemeric)이 아니라 문자형(character)인 'name' 변수를 사용해보겠습니다. 그러면 아래와 같이 'DataError: No numeric types to aggregate'라는 DataError가 납니다. 왜냐하면 값(values) 으로 사용하려는 'name' 변수가 집계가 불가능한 문자형 데이터이기 때문입니다. (numeric only)



In [5]: df.pivot_table(index = 'id', columns='col', values=['name']) # default aggfunc='mean'

Traceback (most recent call last):


  File "<ipython-input-5-9a2cccdff2ef>", line 1, in <module>

    df.pivot_table(index = 'id', columns='col', values=['name'])


  File "C:\Users\admin\Anaconda3\lib\site-packages\pandas\core\groupby.py", line 3048, in _cython_agg_general

    how, numeric_only=numeric_only)


    .... 중간 생략 ....


DataError: No numeric types to aggregate

 




 (2) 'DataError: No numeric types to aggregate' 에러 대응방법은?


집계함수를 aggfunc='first' 로 명시적으로 설정해 줌으로써, 디폴트인 'mean' 을 사용해서 집계하는 것이 아니라 재구조화하는 기준의 테이블의 각 cell의 첫번째 값('first')을 그냥 가져오게끔 해주면 됩니다. 



In [6]: df.pivot_table(index = 'id', columns='col', values=['name'], aggfunc='first')

Out[6]: 

    name   

col   x1 x2

id         

1      a  a

2      b  b

3      c  c

 



집계함수 aggfunc='first' 로 해서 pivot 한 테이블의 값(values)을 하나가 아니라 여러개로 할 수도 있습니다. (이렇게 하면 숫자형 변수 'sum'도 집계를 하는 것이 아니라 각 테이블 cell의 첫번째 값을 가져오게 됨)



In [7]: df.pivot_table(index = 'id', columns='col', values=['name', 'sum'], aggfunc='first')

Out[7]: 

    name    sum    

col   x1 x2  x1  x2

id                 

1      a  a  30  10

2      b  b  70  40

3      c  c  20  8

 



많은 도움이 되었기를 바랍니다. 

Posted by R Friend R_Friend