이번 포스팅에서는 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 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

 

 

pandas DataFrame의 칼럼 순서 변경하기는 https://rfriend.tistory.com/680 를 참고하세요. 

 

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

이번 포스팅이 도움이 되었다면 아래의 '공감~

'를 꾹 눌러주세요. :-)

 

728x90
반응형
Posted by Rfriend
,

지난번 포스팅에서는 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' 



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

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



728x90
반응형
Posted by Rfriend
,

이번 포스팅에서는 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 를 참고하세요. 

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


728x90
반응형
Posted by Rfriend
,

이번 포스팅에서는 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


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

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


728x90
반응형
Posted by Rfriend
,

지난 포스팅에서는 Python pandas DataFrame을 csv 파일로 다운로드 한 후에 로컬에서  PostgreSQL, Greenplum DB에 Copy해서 넣는 방법 (https://rfriend.tistory.com/457) 을 소개하였습니다. 

 이번 포스팅에서는 Python pandas DataFrame을 csv 파일로 다운로드 하는 절차 없이, sqlalchemy engine과 to_sql() 함수를 이용하여 바로 직접 PostgreSQL, Greenplum DB에 쓰는 방법을 소개하겠습니다. 이렇게 하면 다운로드하는 절차가 필요없기 때문에 좀더 간편하고 workflow가 간소화되는 장점은 있는데요, csv로 내려서 copy 하는 것 대비 속도고 조금 더 느리다는 단점이 있습니다. 



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


# make a sample DataFrame

import pandas as pd

score = pd.DataFrame({

        'date': ['2019-07-28']*4, 

        'name': ['kim', 'lee', 'choi', 'park'], 

        'age': [19, 20, 19, 20], 

        'math_score': [91, 95, 92, 70], 

        'pass_yn': [True, True, True, False]}, 

         columns=['date', 'name', 'age', 'math_score', 'pass_yn'])



이제 'score' 라는 이름의 pandas DataFrame을 Postgresql, Greenplum DB에 'score' 라는 Table 이름으로 public schema에 생성해서 써보겠습니다. 

이때 DB connection을 하기 위해 SQLAlchemy로 DB engine 을 생성해줘야 하는데요,
engine = sqlalchemy.create_engine("postgresql://user:password@host:port/database") 
의 순서대로 자신의 DB 설정값을 입력해주면 됩니다. (port 가 5432 디폴트 값이면 생략 가능)

 

import sqlalchemy

from sqlalchemy import create_engine

# engine = sqlalchemy.create_engine("postgresql://user:password@host:port/database")

engine = create_engine("postgresql://postgres:postgres@localhost:5432/postgres") # set yours


engine.execute("DROP TABLE IF EXISTS public.score;") # drop table if exists

score.to_sql(name = 'score', 

             con = engine

             schema = 'public', 

             if_exists = 'fail', # {'fail', 'replace', 'append'), default 'fail'

             index = True, 

             index_label = 'id', 

             chunksize = 2, 

             dtype = {

                     'id': sqlalchemy.types.INTEGER()

                     'date': sqlalchemy.DateTime()

                     'name': sqlalchemy.types.VARCHAR(100)

                     'age': sqlalchemy.types.INTEGER()

                     'math_score': sqlalchemy.types.Float(precision=3)

                     'pass_yn': sqlalchemy.types.Boolean()

                     })



'if_exists' 옵션에는 {'fail', 'replace', 'append'}의 3개가 존재하고, 디폴트는 'fail' 옵션입니다. 

  • if_exists = 'fail' : 같은 이름의 Table이 존재할 경우 ValueError 가 남
  • if_exists = 'replace'같은 이름의 Table이 존재할 경우 기존 Table을 Drop하고 새로운 값을 Insert함
  • if_exists = 'append': 같은 이름의 Table이 존재할 경우 기존 Table에 추가로 새로운 값을 Insert함


index = True 로 설정해주면 pandas DataFrame의 Index도 DB Table에 insert 해주며, index_label = 'xxx'로 index의 칼럼 이름을 부여해줄 수 있습니다. 


chunksize = xx 를 설정해주면 pandas DataFrame 데이터를 xx row 개수 만큼 DB table 에 insert를 해줍니다. 설정해주지 않으면 pandas DataFrame을 통째로 한꺼번에 insert를 합니다. 


dtype 은 pandas DataFrame의 각 변수별로 DB table에 넣어줄 Data Type을 사전형(Dictionary)으로 {'column': data_type} 형식으로 설정해줄 수 있습니다. 위의 예시에서 INTEGER, DateTime(), VARCHAR(), Float(), Boolean 데이터 형태 지정하는 것을 보여주었는데요, 대/소문자, 괄호() 여부를 위의 예시처럼 똑같이 사용해야 합니다. (괄호를 빼먹거나, 대/소문자가 틀리면 에러가 납니다)

참고로, to_sql() 에서 dtype 을 칼럼 별로 설정하지 않으면 전부 'text' 데이터 형태로 해서 DB table에 입력됩니다. 


확인차, DBeaver로 PostgreSQL에 score table을 조회해보겠습니다. Python pandas의 'score' DataFrame이 PostgreSQL의 score table로 데이터가 잘 들어갔네요! 


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

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


728x90
반응형
Posted by Rfriend
,

이번 포스팅에서는 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 


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

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


728x90
반응형
Posted by Rfriend
,

이번 포스팅에서는 Python pandas의 DataFrame을 Postgresql, Greenplum DB에 Copy 해서 집어넣는 방법을 소개하겠습니다. 

먼저 간단한 예제 pandas DataFrame을 만들어보겠습니다. 


import numpy as np

import pandas as pd


# make a DataFrame

school = pd.DataFrame({'region': ['gangnam', 'secho', 'bundang', 'mokdong'], 

                       'student_cnt': [100, 120, 150, 90], 

                       'math_score': [91, 95, 92, 93]}, 

                        columns=['region', 'student_cnt', 'math_score'])


school

Out[02]: 

    region  student_cnt  math_score

0  gangnam          100          91

1    secho          120          95

2  bundang          150          92

3  mokdong           90          93



이제 school 이라는 pandas DataFrame을 아래의 순서대로 DB에 Copy해서 넣어보겠습니다. 

(1) DataFrame을 CSV 파일로 내보내기 (export a DataFrame to CSV file)

(2) Postgresql, Greenplum DB에 연결하고 Table 만들기

(3) Postgresql, Greenplum DB의 Table에 CSV file을 Copy해서 집어넣기


  (1) DataFrame을 CSV 파일로 내보내기 (export a DataFrame to CSV file)


pandas의 to_csv() 메소드를 이용하였으며, index와 header 옵션은 False로 설정해서 CSV 파일에는 포함시키지 않도록 하겠습니다. 


school.to_csv('C:/Users/admin/Documents/data/school.csv', 

              sep=",", 

              na_rep="NaN", 

              index=False

              header=False)

 



  (2) Postgresql, Greenplum DB에 연결하고 Table 만들기

psycopg2 라이브러리를 이용해서 Postgresql, Greenplum DB에 연결해보겠습니다. 아래의 connect() 에는 본인의 DB 설정 정보를 바꾸어서 입력해주면 됩니다. 


# Postgresql DB connect using psycopg2

from psycopg2 import connect

conn = connect(host='localhost',  # set yours

               port=5432, 

               database='postgres', 

               user='postgres', 

               password='postgres')


cur = conn.cursor()


# Create a table at Postgresql public schema with school name

cur.execute("""

    DROP TABLE IF EXISTS school;

    CREATE TABLE school (

        region varchar(100), 

        student_cnt numeric, 

        math_score numeric

    )

""")

conn.commit()

 



  (3) Postgresql, Greenplum DB의 Table에 CSV file을 Copy해서 집어넣기

with open() 으로 로컬에 저장해놓은 school.csv 파일을 읽고, cursor.copy_expert() 를 이용하여 "COPY school FROM STDIN DELIMITER ',' CSV;" 쿼리문을 실행시켜서 CSV 파일을 Table 에 copy 해주겠습니다. 


query = """

    COPY school FROM STDIN DELIMITER ',' CSV;

"""


with open('C:/Users/admin/Documents/data/school.csv', 'r') as f:

    cur.copy_expert(query, f)

    

conn.commit()


# close connection

conn.close()

 


PGAdmin 에 들어가서 school 테이블을 조회해보니 아래처럼 데이터가 잘 copy 되서 들어가 있네요. 


Python에서 DB connect해서 데이터 조회하고 DataFrame으로 만들어서 한번 더 확인을 해보았습니다. 아래와 같이 데이터가 Postgresql DB의 school table에 잘 들어가 있음을 확인할 수 있습니다. 


# check 

cur.execute("SELECT * FROM school;")

school_df = cur.fetchall()

school_df

Out[39]: 

[('gangnam', Decimal('100'), Decimal('91')),

 ('secho', Decimal('120'), Decimal('95')),

 ('bundang', Decimal('150'), Decimal('92')),

 ('mokdong', Decimal('90'), Decimal('93'))] 



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



728x90
반응형
Posted by Rfriend
,

이번 포스팅에서는 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



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



728x90
반응형
Posted by Rfriend
,

이번 포스팅에서는 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

 




사용자 정의함수를 작성하고 df.groupby("grp").apply(UDF) 를 사용하는 방법도 있습니다. apply(UDF_name, arguments) 형식으로 사용자 정의 함수에서 사용했던 매개변수를 같이 넣어주면 됩니다. 매개변수 값을 변경해서 여러번 사용해야 하는 경우에는 아래처럼 사용자 정의 함수를 사용하는게 아무래도 편리하고 코드도 깔끔하겠습니다. 

(물론, 아래의 예의 경우 사용자 정의함수에서 default 값으로 입력해놓은 매개변수 값과 동일하기 때문에 apply(top) 만 해도 결과는 동일합니다.) 



def top(df, n=3, column='val'):

    return df.sort_values(by="val", ascending=False)[:n]

 

df.groupby("grp").apply(top, column="val", n=3)

grpval
grp
a2a8.707697
3a8.288310
0a5.317945
b9b9.460717
5b7.317662
8b6.277714





정렬하는 칼럼이나 Top N개가 고정되어 있거나 일회성인 경우에는 간단하게 lambda 를 사용해서 사용자 정의 함수를 정의해서 사용해도 되겠습니다. 



top2 = lambda x: x.sort_values(by='val', ascending=False)[:3]


df.groupby('grp').apply(top2)

grpval
grp
a2a8.707697
3a8.288310
0a5.317945
b9b9.460717
5b7.317662
8b6.277714

 



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



728x90
반응형
Posted by Rfriend
,

이번 포스팅에서는 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

 



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

728x90
반응형
Posted by Rfriend
,