이번 포스팅에서는 Python pandas DataFrame 이나 Series 내 문자열 칼럼을 숫자형으로 변환(how to convert string columns to numeric data types in pandas DataFrame, Series) 하는 2가지 방법을 소개하겠습니다. 


(1) pd.to_numeric() 함수를 이용한 문자열 칼럼의 숫자형 변환

(2) astype() 메소드를 이용한 문자열 칼럼의 숫자형 변환





  (1) pd.to_numeric() 함수를 이용한 문자열 칼럼의 숫자형 변환


(1-1) 한개의 문자열 칼럼을 숫자형으로 바꾸기



import numpy as np

import pandas as pd


# make a DataFrame

df = pd.DataFrame({'col_str': ['1', '2', '3', '4', '5']})

df

col_str
01
12
23
34
45


# check data types 

df.dtypes

col_str    object
dtype: object


df['col_int'] = pd.to_numeric(df['col_str'])

df

col_strcol_int
011
122
233
344
455


df.dtypes

col_str    object
col_int     int64
dtype: object





(1-2) apply() 함수와 to_numeric() 함수를 사용해 DataFrame 내 다수의 문자열 칼럼을 숫자형으로 바꾸기



# make a DataFrame with 3 string columns

df2 = pd.DataFrame({'col_str_1': ['1', '2', '3'], 

                   'col_str_2': ['4', '5', '6'], 

                   'col_str_3': ['7.0', '8.1', '9.2']})


df2

col_str_1col_str_2col_str_3
0147.0
1258.1
2369.2



df2.dtypes

col_str_1    object
col_str_2    object
col_str_3    object
dtype: object



# convert 'col_str_1' and 'col_str_2' to numeric

df2[['col_int_1', 'col_int_2']] = df2[['col_str_1', 'col_str_2']].apply(pd.to_numeric)

df2

col_str_1col_str_2col_str_3col_int_1col_int_2
0147.014
1258.125
2369.236



df2.dtypes

col_str_1    object
col_str_2    object
col_str_3    object
col_int_1     int64
col_int_2     int64
dtype: object



# convert all columns of a DataFrame to numeric using apply() and to_numeric together

df3 = df2.apply(pd.to_numeric)


df3.dtypes

col_str_1      int64
col_str_2      int64
col_str_3    float64
col_int_1      int64
col_int_2      int64
dtype: object






  (2) astype() 메소드를 이용한 문자열 칼럼의 숫자형 변환


(2-1) DataFrame 내 모든 문자열 칼럼을 float로 한꺼번에 변환하기



df4 = pd.DataFrame({'col_str_1': ['1', '2', '3'], 

                   'col_str_2': ['4.1', '5.5', '6.0']}) 


df4.dtypes

col_str_1    object
col_str_2    object
dtype: object



df5 = df4.astype(float)

df5

col_str_1col_str_2
01.04.1
12.05.5
23.06.0



df5.dtypes

col_str_1    float64
col_str_2    float64
dtype: object





(2-2) DataFrame 내 문자열 칼럼별로 int, float 데이터 형식 개별 지정해서 숫자형으로 변환하기



df6 = df4.astype({'col_str_1': int

                  'col_str_2': np.float})


df6

col_str_1col_str_2
014.1
125.5
236.0



 df6.dtypes

col_str_1      int64
col_str_2    float64
dtype: object






  DataFrame에 문자가 포함된 칼럼이 같이 있을 경우 ValueError


물론 DataFrame 내의 문자열 중에서 숫자가 아니라 문자(character)로 이루어진 문자열(string)이 포함되어 있을 경우 apply(pd.to_numeric) 함수나 DataFrame.astype(int) 메소드를 써서 한꺼번에 숫자형 데이터 형태로 변환하려고 하면 ValueError 가 발생합니다. (너무 당연한 거라서 여기에 써야 하나 싶기도 한데요... ^^;) 


이럴 때는 숫자만 들어있는 문자열 칼럼만을 선택해서 개별적으로 변환을 해주면 됩니다. 


아래는 문자로만 구성된 문자열 'col_2' 를 포함한 df7 데이터프레임을 만들어서 전체 칼럼을 숫자형으로 바꾸려고 했을 때 ValueError 가 발생한 예입니다. 



df7 = pd.DataFrame({'col_1': ['1', '2', '3'], 

                   'col_2': ['aaa', 'bbb', 'ccc']})


df7

col_1col_2
01aaa
12bbb
23ccc



df7.dtypes

col_1    object
col_2    object
dtype: object

 



* ValueError


 

# ValueError

df7 = df7.apply(pd.to_numeric)

--------------------------------------------------------------------------- ValueError Traceback (most recent call last) pandas/_libs/src/inference.pyx in pandas._libs.lib.maybe_convert_numeric() ValueError: Unable to parse string "aaa" During handling of the above exception, another exception occurred: -- 중간 생략 -- ~/anaconda3/lib/python3.6/site-packages/pandas/core/tools/numeric.py in to_numeric(arg, errors, downcast) 124 coerce_numeric = False if errors in ('ignore', 'raise') else True 125 values = lib.maybe_convert_numeric(values, set(), --> 126 coerce_numeric=coerce_numeric) 127 128 except Exception: pandas/_libs/src/inference.pyx in pandas._libs.lib.maybe_convert_numeric() ValueError: ('Unable to parse string "aaa" at position 0', 'occurred at index col_2')




* ValueError


# ValueError

df7 = df7.astype(int)

--------------------------------------------------------------------------- ValueError Traceback (most recent call last) <ipython-input-124-f50dad302c83> in <module>() ----> 1 df7 = df7.astype(int) -- 중간 생략 --

~/anaconda3/lib/python3.6/site-packages/pandas/core/dtypes/cast.py in astype_nansafe(arr, dtype, copy) 623 elif arr.dtype == np.object_ and np.issubdtype(dtype.type, np.integer): 624 # work around NumPy brokenness, #1987 --> 625 return lib.astype_intsafe(arr.ravel(), dtype).reshape(arr.shape) 626 627 if dtype.name in ("datetime64", "timedelta64"): pandas/_libs/lib.pyx in pandas._libs.lib.astype_intsafe() pandas/_libs/src/util.pxd in util.set_value_at_unsafe()  

ValueError: invalid literal for int() with base 10: 'aaa' 





 문자열을 숫자형으로 변환 시 ValueError 를 무시하기: df.apply(pd.to_numeric, errors = 'coerce') 



위의 예와는 조금 다르게 문자형을 숫자형으로 변환하려는 칼럼이 맞는데요, 값 중에 몇 개가 실수로 숫자로 된 문자열이 아니라 문자로 된 문자열이 몇 개 포함되어 있다고 해봅시다. 이럴 경우 문자열을 숫자로 파싱할 수 없다면서 ValueError가 발생하는데요, 문자가 포함되어 있는 경우는 강제로 'NaN'으 값으로 변환하고, 나머지 숫자로된 문자열은 숫자형으로 변환해주려면 errors = 'coerce' 옵션을 추가해주면 됩니다. 


 

df8 = pd.DataFrame({'col_1': ['1', '2', '3'], 

                   'col_2': ['4', 'bbb', '6']})


df8

col_1col_2
014
12bbb
236



df8 = df8.apply(pd.to_numeric)

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
pandas/_libs/src/inference.pyx in pandas._libs.lib.maybe_convert_numeric()

ValueError: Unable to parse string "bbb"

During handling of the above exception, another exception occurred:

ValueError                                Traceback (most recent call last)
<ipython-input-130-9e8d711c10d5> in <module>()
----> 1 df8 = df8.apply(pd.to_numeric)

~/anaconda3/lib/python3.6/site-packages/pandas/core/frame.py in apply(self, func, axis, broadcast, raw, reduce, args, **kwds)
   4260                         f, axis,
   4261                         reduce=reduce,
-> 4262                         ignore_failures=ignore_failures)
   4263             else:
   4264                 return self._apply_broadcast(f, axis)

~/anaconda3/lib/python3.6/site-packages/pandas/core/frame.py in _apply_standard(self, func, axis, ignore_failures, reduce)
   4356             try:
   4357                 for i, v in enumerate(series_gen):
-> 4358                     results[i] = func(v)
   4359                     keys.append(v.name)
   4360             except Exception as e:

~/anaconda3/lib/python3.6/site-packages/pandas/core/tools/numeric.py in to_numeric(arg, errors, downcast)
    124             coerce_numeric = False if errors in ('ignore', 'raise') else True
    125             values = lib.maybe_convert_numeric(values, set(),
--> 126                                                coerce_numeric=coerce_numeric)
    127 
    128     except Exception:

pandas/_libs/src/inference.pyx in pandas._libs.lib.maybe_convert_numeric()

ValueError: ('Unable to parse string "bbb" at position 1', 'occurred at index col_2')



df8 = df8.apply(pd.to_numeric, errors = 'coerce')

df8

col_1col_2
014.0
12NaN
236.0




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


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



728x90
반응형
Posted by Rfriend
,

이번 포스팅에서는 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 으로 프로그래밍을 하다보면 의도했던, 의도하지 않았던 간에 예외를 처리해야 하는 상황에 맞닥드리게 됩니다. 이때 에러를 발생(Raise Error) 시킬 수도 있고 회피할 수도 있으며, 필요에 따라서는 예외 처리를 해야 할 수도 있습니다. 


이번 포스팅에서는 Python에서 예외를 처리하는 4가지 try, except, else, finally 절(clause)을 소개하겠습니다. 




  • try 에는 정상적으로 실행할 프로그램 코드(code block) 써줍니다. 

  • except 절에는 의 try 절에서 실행한 코드에 예외가 발생했을 경우에 실행할 코드를 써줍니다. 

  • else 절에는 앞의 try 절에서 실행한 코드에 예외가 발생하지 않은 경우에 실행할 코드를 써줍니다. 

  • finally 절에는 try 절에서의 예외 발생 여부에 상관없이 항상(always execute) 마지막에 실행할 코드를 써줍니다. 


간단한 예로서, 두개의 숫자를 매개변수로 받아서 나눗셈을 하는 사용자 정의함수를 try, except, else, finally 의 예외절을 사용하여 정의해 보겠습니다. 


try, except, else, finally 절의 끝에는 콜론(:)을 붙여주며, 그 다음줄에 코드 블락은 들여쓰기(indentation)을 해줍니다. 

except의 경우 'except:' 만 사용해도 되고, 아래 예의 'except ZeorDivisionError as zero_div_err:' 처럼 Built-in Exception Class를 사용해서 에러를 명시적으로 써줄 수도 있습니다. (본문의 제일 밑에 Python Built-in Exception Class 의 계층 구조 참조)



# Python Exceptions: try, except, else, finally

def divide(x, y):

    try:

        result = x / y

    except ZeroDivisionError as zero_div_err:

        print("Except clause:", zero_div_err)

    else:

        print("Else clause: The result of division is", result)

    finally:

        print("Finally clause is executed.")

 




(1) try 절 정상 실행 시 (executed nomally): try --> else --> finally


두 숫자 x, y를 인자로 받아서 나눗셈을 하는 사용자 정의함수 divide(x, y) 에 x=1, y=2 를 넣어서 정상적으로 코드가 수행되었을 때의 결과를 보겠습니다.  마지막으로 finally 절이 실행되었습니다. 


In [1]: def divide(x, y):

   ...: try:

   ...: result = x / y

   ...: except ZeroDivisionError as zero_div_err:

   ...: print("Except clause:", zero_div_err)

   ...: else:

   ...: print("Else clause: The result of division is", result)

   ...: finally:

   ...: print("Finally clause is executed.")

   ...:

   ...:

In [2]: divide(1, 2)

Else clause: The result of division is 0.5

Finally clause is executed. 




(2) try 절 실행 중 예외 발생 시 (exception occurred): try --> except --> finally


1을 '0'으로 나누라고 하면 'except ZeroDivisionError as zero_div_err:' 의 except 절이 실행됩니다. 그리고 마지막으로 finally 절이 실행되었습니다. 


In [3]: divide(1, 0)

Except clause: division by zero

Finally clause is executed.




(3) try 절 Error 발생 시: try --> finally  --> Raise Error


divide(x, y) 사용자 정의함수에 숫자를 인자로 받는 매개변수에 문자열(string)을 입력하는 경우 TypeError가 발생하겠지요? 이때 finally를 먼저 실행하고, 그 후에 TypeError 를 발생시킵니다. 


In [4]: divide("1", "2")

Finally clause is executed.

Traceback (most recent call last):


File "<ipython-input-4-bbf78a5b43b9>", line 1, in <module>

divide("1", "2")


File "<ipython-input-1-78cbb56f9746>", line 3, in divide

result = x / y


TypeError: unsupported operand type(s) for /: 'str' and 'str'


Traceback (most recent call last):


File "<ipython-input-4-bbf78a5b43b9>", line 1, in <module>

divide("1", "2")


File "<ipython-input-1-78cbb56f9746>", line 3, in divide

result = x / y


TypeError: unsupported operand type(s) for /: 'str' and 'str' 




(4) Try Except 절에서 에러 발생 시 Exception Error 이름과 Error message 출력



import numpy as np


arr = np.array([[1., 2., 3.], [4.0, 5., 6.]])

print(arr)

[Out]
[[1. 2. 3.]
 [4. 5. 6.]]


# It will not work and eraise an error

try:

    arr.reshape(5, -1)

except Exception as e:

    print(f"{type(e).__name__}: {e}")

[Out] 
ValueError: cannot reshape array of size 6 into shape (5,newaxis)





[ 참고: The Class Hierarchy of Python Built-in Exceptions ]

(* source: https://docs.python.org/3/library/exceptions.html)


 BaseException

 +-- SystemExit

 +-- KeyboardInterrupt

 +-- GeneratorExit

 +-- Exception

      +-- StopIteration

      +-- StopAsyncIteration

      +-- ArithmeticError

      |    +-- FloatingPointError

      |    +-- OverflowError

      |    +-- ZeroDivisionError

      +-- AssertionError

      +-- AttributeError

      +-- BufferError

      +-- EOFError

      +-- ImportError

      |    +-- ModuleNotFoundError

      +-- LookupError

      |    +-- IndexError

      |    +-- KeyError

      +-- MemoryError

      +-- NameError

      |    +-- UnboundLocalError

      +-- OSError

      |    +-- BlockingIOError

      |    +-- ChildProcessError

      |    +-- ConnectionError

      |    |    +-- BrokenPipeError

      |    |    +-- ConnectionAbortedError

      |    |    +-- ConnectionRefusedError

      |    |    +-- ConnectionResetError

      |    +-- FileExistsError

      |    +-- FileNotFoundError

      |    +-- InterruptedError

      |    +-- IsADirectoryError

      |    +-- NotADirectoryError

      |    +-- PermissionError

      |    +-- ProcessLookupError

      |    +-- TimeoutError

      +-- ReferenceError

      +-- RuntimeError

      |    +-- NotImplementedError

      |    +-- RecursionError

      +-- SyntaxError

      |    +-- IndentationError

      |         +-- TabError

      +-- SystemError

      +-- TypeError

      +-- ValueError

      |    +-- UnicodeError

      |         +-- UnicodeDecodeError

      |         +-- UnicodeEncodeError

      |         +-- UnicodeTranslateError

      +-- Warning

           +-- DeprecationWarning

           +-- PendingDeprecationWarning

           +-- RuntimeWarning

           +-- SyntaxWarning

           +-- UserWarning

           +-- FutureWarning

           +-- ImportWarning

           +-- UnicodeWarning

           +-- BytesWarning

           +-- ResourceWarning



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

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



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
,

이번 포스팅에서는 사용자 정의함수(User Defined Function)에서 가변 매개변수(variable-length arguments, arbitrary arguments)의 위치에 따라서 일반 매개변수의 Keyword Argument 호출 여부에 따른 SyntaxError, TypeError 가 발생하는 현상을 살펴보고, 올바른 사용법을 소개하겠습니다. 


이게 은근히 헷갈리는 면이 있으므로 이번에 정확하게 알아두면 좋겠습니다. 





매개변수의 수를 다르게 해서 사용할 수 있는 가변 매개변수(variable-length arguments, arbitrary arguments) 위치가 뒤에 있는지, 아니면 앞에 있는지에 따라 2개 유형으로 나누어서 Keyword argument 의 올바른 사용법과 Error 발생 유형을 설명하겠습니다. 



  (1) 이름을 지정한 일반 매개변수를 앞에, 가변 매개변수를 뒤에 정의한 함수

      (Keyword argument First, Variable-length Arguments Second)


(1-1) 올바른 사용법: Keyword argument 사용 안함 (Without Keyword argument name)


In [1]: def repeat_str_KeyArg_first(repeat_num, *strings):

   ...: result = [repeat_num * strings]

   ...: return result

   ...:

   ...:


In [2]: repeat_str_KeyArg_first(3, 'a', 'b', 'c')

   ...:

Out[2]: [('a', 'b', 'c', 'a', 'b', 'c', 'a', 'b', 'c')] 



(1-2) Keyword argument를 사용해서 SystaxError가 발생하는 틀린 사용법
 => SyntaxError: positional arguments follows keyword argument


In [1]: def repeat_str_KeyArg_first(repeat_num, *strings):

   ...: result = [repeat_num * strings]

   ...: return result

   ...:

In [3]: repeat_str_KeyArg_first(repeat_num = 3, 'a', 'b', 'c') # SyntaxError

   ...:

File "<ipython-input-3-2047f5ba4020>", line 1

repeat_str_KeyArg_first(repeat_num = 3, 'a', 'b', 'c')

^

SyntaxError: positional argument follows keyword argument


File "<ipython-input-3-2047f5ba4020>", line 1

repeat_str_KeyArg_first(repeat_num = 3, 'a', 'b', 'c')

^

SyntaxError: positional argument follows keyword argument





  (2) 가변 매개변수를 앞에, 이름을 지정한 일반 매개변수를 뒤에 정의한 함수

      (Variable-length Arguments First, Keyword argument Second)


(2-1) 올바른 사용법: Keyword argument 사용함 (With Keyword argument name)


In [4]: def repeat_str_VarArg_first(*strings, repeat_num):

   ...: result = [repeat_num * strings]

   ...: return result

   ...:

   ...:


In [5]: repeat_str_VarArg_first('a', 'b', 'c', repeat_num = 3) # works well

   ...:

Out[5]: [('a', 'b', 'c', 'a', 'b', 'c', 'a', 'b', 'c')] 



(2-2) TypeError 발생하는 틀린 사용법 : 

  => TypeError: function() missing 1 required keyword-only argument: 'keyword_arg'


In [4]: def repeat_str_VarArg_first(*strings, repeat_num):

   ...: result = [repeat_num * strings]

   ...: return result

   ...:

   ...:

In [6]: repeat_str_VarArg_first('a', 'b', 'c', 3) # TypeError

   ...:

Traceback (most recent call last):


File "<ipython-input-6-13d658b54364>", line 1, in <module>

repeat_str_VarArg_first('a', 'b', 'c', 3)


TypeError: repeat_str_VarArg_first() missing 1 required keyword-only argument: 'repeat_num'


Traceback (most recent call last):


File "<ipython-input-6-13d658b54364>", line 1, in <module>

repeat_str_VarArg_first('a', 'b', 'c', 3)


TypeError: repeat_str_VarArg_first() missing 1 required keyword-only argument: 'repeat_num' 



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

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



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, 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, 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 


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

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

728x90
반응형
Posted by Rfriend
,

이번 포스팅에서는 빠르고 메모리를 효율적으로 사용해서 반복자((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] 



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

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


728x90
반응형
Posted by Rfriend
,