MINERVA/Python 2023. 2. 11. 09:56
반응형

프로그램 테스트를 진행 하다가 예상치 못한 동작이 발견되어, 원인을 파악해 보니, 공백 처리가 미진하게 되어 발생되었음을 확인하게되었습니다. 이 이슈는 정말 아주 아주 오랜(?)만에 경험하게 되었습니다.

 

공백(Blank)는 두가지 의미로 생각해야 합니다.

진짜 아무것도 없다? 아니면, 화면에 보이지 않는 어떤 값이 있는건지?

 

간단히 생각의 흐름대로 아래와 같이 정리하여 보았습니다.

 

1. 예제 데이타

- 기대한 데이타: 값이 없는 경우(ex: 공백 등) 모두 0으로 설정( dataframe = dataframe.fillna(0))

- 예상치 못한 데이타: 아래와 같이 0으로 변경되지 않고 빵구(?),  정체 불명의 공백이 그대로 있음

    저 공백에는 머가 있는거지?

아이템           경험가중치
0                  0
1                  0
2                  0
:                  :
60                 0
61                 0
62                 
63                 
64                 0
65                 0
66                 
67                 
68                 0
:                  :
:                  :
106                0
107                0
108                0
109                
110                0
111                
112                0
:                  :
127       6,243,841
128      23,787,440
129      11,598,306
130       5,240,070
131       5,933,144
:                  :
:                  :

2. 빵구(?) 정체 확인 

 

2.1 접근1

-  아래와 같이 null 이 있는지 확인

print(expDf.info())
print(expDf.isnull())
RangeIndex: 2690 entries, 0 to 2689
Data columns (total 1 columns):
 #   Column  Non-Null Count  Dtype 
---  ------  --------------  ----- 
 0   경험가중치   2690 non-null   object
dtypes: object(1)
memory usage: 21.1+ KB
None
      경험가중치
0     False
1     False
2     False
3     False
4     False
:      :
:      :
2688  False
2689  False

- 위와 같이, 공백이 없다는 것을 확인함. 

 

2.2 접근2

- 각 컬럼 값의 길이를 찍어 봄

print(expDf['경험가중치'].str.len())
0        NaN
1        NaN
:         :
61       NaN
62       2.0
63       2.0
64       NaN
65       NaN
66       2.0
67       2.0
68       NaN
:        :
:        :
108      NaN
109      2.0
110      NaN
111      2.0
112      NaN
:        :
124      NaN
125      NaN
126      NaN
127     10.0
:       :
2688    11.0
2689    11.0

-  길이를  확인하여 보니, 어떤 값이 들어 가 있다는 것을 확신하게 됨

 

2.3 접근3

- 해당 행(62번행)  hex값을 확인함

print(expDf['경험가중치'].iloc[62])

print(type(expDf['경험가중치'].iloc[61]))
print(type(expDf['경험가중치'].iloc[62]))

# str -> hex
# value = ''.join(format(ord(i), '08b') for i in expDf['경험가중치'].iloc[62])
#print(str(value))
print(expDf['경험가중치'].iloc[62].encode('utf-8').hex())
<class 'int'>
<class 'str'>
c2a020

- 값을 확인해 보면, 62번 행은 string 타입이고, 이 값의 hex값을 위와 같이 확인할수 있다.

  그리고, hex값 20은 SPACE를 의미 한다는 것을 확인할수 있게 됨

 

3. 해결방법

- 원인 확인: 해당 공백이 SPACE에 의해서 발생했음을 확인함.

expDf['경험가중치'] = expDf['경험가중치'].replace(r'^\s+$', np.nan, regex=True)
expDf['경험가중치'] = expDf['경험가중치'].replace(np.nan, 0)

- 'SPACE' 공백을 NaN으로 전환하고, 이 값을 0으로 바꿈

아이템             경험가중치
:                    :
59                   0
60                   0
61                   0
62                   0
63                   0
64                   0
65                   0
66                   0
67                   0
:                    :

정상적으로 결과를 나왔음을 확인

 

4. 결과

- NULL관련된 이슈는 참으로 오래된 이슈(?)여서 재밌기도 하였지만, 느닷없이 발생했을때는 좀 놀랐네요.

 

반응형
posted by choiwonwoo
:
MINERVA/Python 2022. 11. 16. 18:55
반응형

개발을 진행하다 보면, 두개의 리스트중 하나를 key로 하고, 나머지 하나의 리스트를 value 연결합니다.

이때, C++/Java/c#등의 언어 map을 사용하고, Python은 dictionary를 사용하게 됩니다.

Python은 다른언어에 비교해서 문법적으로 매우 직관적입니다. 대신, 다른 언어와 다르게 zip()함수를 사용합니다.

 

[코드예제]

keyList     = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j']
valueList   = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

pairDic = {key: value for key, value in zip(keyList,valueList)}
print(pairDic)
print(pairDic['j'])
print(pairDic['e'])

[코드결과]

{'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5, 'f': 6, 'g': 7, 'h': 8, 'i': 9, 'j': 10}
10
5

반응형
posted by choiwonwoo
:
MINERVA/Python 2022. 11. 12. 04:38
반응형

행(row)과 열(column) 형태인 datafram을 결합하기 위해서 concat() 함수를 사용합니다.

사용 방법은 매우 직관적이며 아래의 샘플코드를 한번 보시면 고등학생때 수업시간에 배운 집합을 생각하시면 매우 간단합니다.

 

1. 예제1

SampleDf1 = {'A': ['A1', 'A2', 'A3', 'A4'],
             'B': ['B1', 'B2', 'B3', 'B4'],
             'C': ['C1', 'C2', 'C3', 'C4'],
             }

df1 = pd.DataFrame(SampleDf1)
print(df1)


SampleDf2 = {'A': ['A1', 'A2', 'A3', 'A4'],
             'B': ['B1', 'B2', 'B3', 'B4'],
             'C': ['C1', 'C2', 'C3', 'C4'],
             }
df2 = pd.DataFrame(SampleDf2)
print(df2)

(실행결과)

    A   B   C
0  A1  B1  C1
1  A2  B2  C2
2  A3  B3  C3
3  A4  B4  C4
    A   B   C
0  A1  B1  C1
1  A2  B2  C2
2  A3  B3  C3
3  A4  B4  C4

unionDf = pd.concat([df1, df2])

(실행결과)

    A   B   C
0  A1  B1  C1
1  A2  B2  C2
2  A3  B3  C3
3  A4  B4  C4
0  A1  B1  C1
1  A2  B2  C2
2  A3  B3  C3
3  A4  B4  C4

 

unionDf = pd.concat([df1, df2], ignore_index=True)

- 인덱스 새롭게 설정함

(실행결과)    

A   B   C
0  A1  B1  C1
1  A2  B2  C2
2  A3  B3  C3
3  A4  B4  C4
4  A1  B1  C1
5  A2  B2  C2
6  A3  B3  C3
7  A4  B4  C4

unionDf = pd.concat([df1, df2],axis=1) 
print(unionDf)

- 옆으로 데이타를 연결

(실행결과)

    A   B   C   A   B   C
0  A1  B1  C1  A1  B1  C1
1  A2  B2  C2  A2  B2  C2
2  A3  B3  C3  A3  B3  C3
3  A4  B4  C4  A4  B4  C4

 

unionDf = pd.concat([df1,df2],ignore_index=True).drop_duplicates(keep='first')
print(unionDf)

# 중복행 제거: drop_duplicates() 사용

(실행결과)

    A   B   C
0  A1  B1  C1
1  A2  B2  C2
2  A3  B3  C3
3  A4  B4  C4

unionDf = pd.concat([df1,df2],ignore_index=True).drop_duplicates(keep='last')
print(unionDf)

(실행결과)

    A   B   C
4  A1  B1  C1
5  A2  B2  C2
6  A3  B3  C3
7  A4  B4  C4

 

2. 예제2

SampleDf1 = {'A': ['A1', 'A2', 'A3', 'A4'],
             'B': ['B1', 'B2', 'B3', 'B4'],
             'C': ['C1', 'C2', 'C3', 'C4'],
             }

df1 = pd.DataFrame(SampleDf1)
print(df1)

SampleDf2 = {'C': ['C1', 'C2', 'C3', 'C4'],
             'D': ['D1', 'D2', 'D3', 'D4'],
             'E': ['E1', 'E2', 'E3', 'E4'],
             'F': ['F1', 'F2', 'F3', 'F4'],
             }
df2 = pd.DataFrame(SampleDf2)
print(df2)

unionDf = pd.concat([df1, df2])
print(unionDf)

(실행결과)

    A   B   C
0  A1  B1  C1
1  A2  B2  C2
2  A3  B3  C3
3  A4  B4  C4
    C   D   E   F
0  C1  D1  E1  F1
1  C2  D2  E2  F2
2  C3  D3  E3  F3
3  C4  D4  E4  F4
     A    B   C    D    E    F
0   A1   B1  C1  NaN  NaN  NaN
1   A2   B2  C2  NaN  NaN  NaN
2   A3   B3  C3  NaN  NaN  NaN
3   A4   B4  C4  NaN  NaN  NaN
0  NaN  NaN  C1   D1   E1   F1
1  NaN  NaN  C2   D2   E2   F2
2  NaN  NaN  C3   D3   E3   F3
3  NaN  NaN  C4   D4   E4   F4

unionDf = pd.concat([df1, df2], ignore_index=True)
print(unionDf)

(실행결과)

     A    B   C    D    E    F
0   A1   B1  C1  NaN  NaN  NaN
1   A2   B2  C2  NaN  NaN  NaN
2   A3   B3  C3  NaN  NaN  NaN
3   A4   B4  C4  NaN  NaN  NaN
4  NaN  NaN  C1   D1   E1   F1
5  NaN  NaN  C2   D2   E2   F2
6  NaN  NaN  C3   D3   E3   F3
7  NaN  NaN  C4   D4   E4   F4

unionDf = pd.concat([df1, df2],axis=1)
print(unionDf)

(실행결과)

     A     B   C    C     D    E   F
0  A1  B1  C1  C1  D1  E1  F1
1  A2  B2  C2  C2  D2  E2  F2
2  A3  B3  C3  C3  D3  E3  F3
3  A4  B4  C4  C4  D4  E4  F4

 

3.정리

세부적인 설명보다는 샘플코드와 실행결과를 보면 이해가 쉽게 될것으로 생각되어 코드와 실행결과를 남겼습니다.

 

반응형
posted by choiwonwoo
:
MINERVA/Python 2022. 11. 7. 16:42
반응형

Dataframe 객체를 추출(?)이후, 정보 흐름 파악을 위해 컬럼 또는 로우간 누적 합/곱을 합니다.

 

이때 사용하는 함수로 cumsum / cumprod

가 있습니다.


위에서부터 아래로 한줄씩 덧셈/곱셈을 누적합니다.

 

1. 예제 데이타 프레임

 

df = pd.DataFrame({'A': [1, 2, 3],
                   'B': [4, 5, 6],
                   'C': [7, 8, 9]}, index=['1', '2', '3'])

print(df)

[결과]

   A  B  C
1  1  4  7
2  2  5  8
3  3  6  9

 

2. 누적합 예제

############################
# 행누적합
print()
print(df.cumsum(axis=1))

# 열누적합
print()
print(df.cumsum(axis=0))

[결과]

   A  B   C
1  1  5  12
2  2  7  15
3  3  9  18

   A   B   C
1  1   4   7
2  3   9  15
3  6  15  24

 

3. 누적곱 예제

############################
# 행누적곱
print()
print(df.cumprod(axis=1))

# 열누적곱
print()
print(df.cumprod(axis=0))

[결과]

   A   B    C
1  1   4   28
2  2  10   80
3  3  18  162

   A    B    C
1  1    4    7
2  2   20   56
3  6  120  504

 

4. 정리

개발 언어중에, 위의 기능은 python dataframe에만 있는것으로 알고 있다.

C/C++, Java등에서 해당 기능을 구현할려면 루핑을 돌려서 처리하였는데, 역시 Python은 데이타 분석을 위한 다양한 기능이 기본으로 제공되는 것 같다.

반응형
posted by choiwonwoo
:
MINERVA/Python 2022. 9. 3. 21:58
반응형

C/C++을 오랫동안(음...20년이 넘나?)사용하다가, Data type assignment 언어인 Python은 처음부터 접근과 사용이 매우 수월(?)했습니다. 그렇지만, 문법(?)적으로 동적으로 변수를 선언 및 사용하는 방법은 다른 개발 언어와 비교했을때 확실히 다름(?)이 있어, 아래와 같이 간단히 정리하고자 합니다.

# 지역별 APT 평균 가격
# 강남구,서초구,........
regionPrice = ['14억', '13억', '9억', '7억', '6억']
#regionMajor = [....]

# 동적 변수 선언 및 값 할당
for i in range(0, len(regionPrice)):
    locals()['df{}'.format(i)] = regionPrice[i]

# 동적 변수 접근
for i in range(0, len(regionPrice)):
    df = locals()['df{}'.format(i)]
    print(df)

프로젝트에 사용된 일부 코드를 발취하여 편집하였습니다.

글로벌 변수로 사용하기 위해서는 locals() --> Globals()로 변경하면 됩니다.

 

기술적인 이론을 이해하기 위해서는, Python의 메모리 관리와 인터프린터 언어의 특성에 대해서 감(?)을 잡아함. 이부분은시간이 날때 따로 정리 하도록하겠습니다.

 

반응형
posted by choiwonwoo
:
MINERVA/Python 2022. 8. 19. 14:21
반응형

개발 언어를 여러개 사용하다보니 순간 순간 헷갈리는 경우가 있어 나를 위해 기록으로 남김

 

[C/C++]
 for (int i = 0; i < 10; i++) {
    printf("%d\n", i);
}

[PYTHON]
for i in range(0, 10, 1): #range(시작,끝,증가값)
  print i

 

 

반응형
posted by choiwonwoo
:
MINERVA/Python 2022. 8. 16. 07:57
반응형

해당 일이 휴일 또는 공휴일인지 확인

 

# 공휴일 체크 모듈:

pytimekr

# 샘플 코드

import datetime
from pytimekr import pytimekr

# 주말(weekend) & 연휴(holiday)
def CheckOffDay(d):
    holidayList = pytimekr.holidays()
    bHoliday = holidayList.__contains__(d)
    bWeekday = d.weekday() > 4
    return(bWeekday or bHoliday)


if __name__ == '__main__':
    # 리턴: 리스트 형태로 관련값 반환: %Y-%m-%d
    #holidayList = pytimekr.holidays()
    #for index in holidayList:
    #    print(index)

    # 시분초 없이
    dtTest = datetime.date(2022, 9, 8)
    print(type(dtTest))
    print(dtTest)

    # for manual test
    strToday = '20220815'
    dtToday = datetime.datetime.strptime(strToday, '%Y%m%d')
    print(type(dtToday))
    print(dtToday.date())

    print(CheckOffDay(dtToday.date()))

# CheckOffDay()를 통해서, 해당일이 공휴일 또는 주말이면 True가 리턴됨

 

반응형
posted by choiwonwoo
:
MINERVA/Python 2022. 8. 16. 07:47
반응형

리스트내에 값(value, element)가 존재하는지 확인 하는 3가지 방법

 

아래 코드는 광복절(8월 15일)이 리스트 내에 존재하는지 확인

 

# 리스트 안에 값(value, element)가 있는지 확인
dtDay = datetime.date(2022, 8, 15)
holidayList = pytimekr.holidays()

# 방법1:
bOffDay = holidayList.__contains__(dtDay)
print(f'[방법 1:] {bOffDay}')

# 방법2:
bOffDay = False
if dtDay in holidayList:
    bOffDay = True
print(f'[방법 2:] {bOffDay}')

# 방법3:
bOffDay = False
if holidayList.count(dtDay) > 0:
    bOffDay = True
print(f'[방법 3:] {bOffDay}')

[결과]

[방법 1:] True
[방법 2:] True
[방법 3:] True

반응형
posted by choiwonwoo
:
MINERVA/Python 2022. 8. 15. 08:31
반응형

아래 코드는 특정 날짜를 기준으로 offset day를 구하는 코드 입니다.

이때, working day를 기준으로 해당 날짜를 예제입니다.

 

사용 용례: 오늘을 기준으로 working day 5일전의 날짜는 언제인가?(주말제외)

 

# working days 계산: 오늘 기준 5일전(당일제외) 날짜 구함(단, 주말을 제외)
nBefore = 5
PivotDatetime = datetime.datetime.now()
BeforeDatatime = PivotDatetime - datetime.timedelta(days=nBefore)

# BeforeDatatime 부터  PivotDatetime 으로 주말이 몇번 있는지 확인
nLoop = 0
nOffday = 0
while nLoop < nBefore:
    if CheckWeekend(BeforeDatatime):
        nOffday = nOffday +1
    BeforeDatatime = BeforeDatatime + datetime.timedelta(days=1)
    nLoop = nLoop + 1

#
BeforeDatatime = PivotDatetime - datetime.timedelta(days=(nBefore+nOffday))
strBeforeDay = BeforeDatatime.strftime('%Y%m%d%H%M%S')

#
print(f'{BeforeDatatime} {PivotDatetime}')

주말을 체크하는 함수

# return: Bool
def CheckWeekend(d):
    return d.weekday() > 4

 

반응형
posted by choiwonwoo
:
MINERVA/Python 2022. 8. 13. 06:42
반응형

파이썬의 데이타 변환은 이전 블로그 글에서 소개드린 대로 매우 직관적으로 됩니다. 하지만, 다른 객체의 원소로 포함된 데이타 타입의 변환은 익숙하지 않으면 실수할 수 있어 정리하고자 합니다.

 

# List 원소 str원소를 int로 변환
stringList = ['1','2','3','4','5']
print(type(stringList))
print(stringList)

# 방법1: map 사용
intList1 = list(map(int,stringList))
print(type(intList1))
print(intList1)

# 방법2: list 사용
intList2 = [int(n) for n in stringList]
print(type(intList2))
print(intList2)

[결과]

['1', '2', '3', '4', '5']
<class 'list'>
[1, 2, 3, 4, 5]
<class 'list'>
[1, 2, 3, 4, 5]

 

cf) 추가 적으로 위의 방법은 python 3인 경우에 적용되며, python 2를 사용한다면 아래를 사용

intList1 = map(int, stringList)
print(type(intList1))
print(intList1)
반응형
posted by choiwonwoo
: