개발 협업을 진행하다면, 많은 이슈(?)가 발생하기는 한데, 이 부분은 조금 까다롭게 느껴저 정리를 진행합니다.
현재 개발이 유닉스(리눅스)와 윈도우 모두에서 진행되고, 공통기능은 유지보수 및 개발 속도등을 생각해서, 공통 라이브러리를 통해서 진행되어 왔습니다.
그러던중 몇가지 조건이 더 있기는 하지만, 필요한 기능은 단순히 '최근 적재된 두 파일의 데이타 차이'를 비교가하는 기능입니다.
그런데 이 부분이 윈도우와 유닉스간데 차이가 있는 부분이 있습니다.
1. 윈도우
윈도우는 파일을 '생성시간'과 '변경시간'으로 관리함
- 파일 생성: '생성시간' 과 '수정시간'으로 관리되고, '생성시간' = '수정시간'
- 파일 변경: '생성시간'은 유지, '수정시간'은 변경됨
- 파일 복사: 새로운 '생성시간' 과 '수정시간'이 생성되고, 두 값은 같다.
- 파일 이동: '생성시간'은 유지, '수정시간'은 변경됨
(API)
os.path.getctime(): 생성 시간 (파일을 처음 만든 날)
os.path.getmtime(): 수정 시간 (파일 내용을 마지막으로 업데이트한 날)
2. 유닉스(리닉스)
유닉스는 윈도우와 파일 관리 체계가 다름: 가장 큰차이는 '생성시간'이라는 개념 없음
| 종류 | 이름 | 의미 | 업데이트 시점 |
| mtime | 수정시간 | 내용수정시간 | 파일의 **데이터(내용)**가 수정되었을 때 |
| atime | 접근시간 | 접근시간 | 파일을 열거나 읽었을 때 |
| ctime | 변경시간 | 상태변경시간 | 파일의 권한, 소유자, 이름, 내용 등이 바뀔 때 |
윈도우와 다르게, 리눅스의 ctime은 변경시간입니다. 파일의 메타데이터(권한, 파일명 등)가 바뀌면 갱신됩니다.
파일 내용을 업데이트하면 mtime과 ctime이 둘 다 바뀝니다.
파일 내용 그대로 두고 권한만 바꾸면 ctime만 바뀝니다.
3. 정리
- 운영체제와 상관없이 가장 일관된 값은 mtime (수정 시간)입니다.
# 유닉스/리눅스/윈도우 공통으로 '파일 내용이 바뀐 시점'을 가져옴
mtime = os.path.getmtime(file_path)
- 생성시간이 필요한 경우는 별도의 로직 처리가 필요함
데이타 관점에서 정의하면 NaN은 '빈칸(결측치)' 또는 '값이 없다'를 의미한다. 이 내용을 시각적으로 정의하면, 엑셀 cell이 하얗게 비여 있는 상태를 의미한다.
1. NaN(Not a Number)
1.1 왜? 이것을 '빈칸'이라고 하지 않지 않고, NaN이라고 할까?
제 짐작으로는 프로그래밍 언어의 데이타 타입에 따라 다르게 인식하기 때문일듯하다.
1) 숫자 상태에서 빈칸: NaN(float로 취급)
2) 객체 상태에서 빈칸: None
3) 문자열에서 빈칸:""(Empty String, 이건 내용이 없는것이지 NaN이 아니다!)
위와 같이 데이타 타입에 따라 의미하는 바가 다르기때문에 NaN이라는 것을 만들어 낸듯하다.
1.2. NaN의 특징
1) 연상 불능: NaN에 숫자를 더하거나 곱해도 무조건 NaN이 됨
2) 자기 자신 비교 불가
- if NaN == NaN 은 언제나 False이다.그래서, df == np.nan 대신 반드시 df.isna()를 사용해야함
2. inf(Infinity:무한대)
- 단순히 '엄청나게 큰 수'가 아닌, 계산이 불가능할 정도로 커진 상태 의미
- 수학에서 말하는 무한대 개념을 컴퓨터에 적용하기 위해서 만들어 냄
2.1 언제 발생
- 숫자를 0으로 나눌때 발생
print(10 / 0) # 일반 파이썬에선 ZeroDivisionError 발생
print(np.array([10]) / 0) # 넘파이/판다스에선 [inf] 발생
- 양의 무한대 (inf): $10 / 0$ 처럼 양수를 0으로 나눴을 때
- 음의 무한대 (-inf): $-10 / 0$ 처럼 음수를 0으로 나눴을 때
2.2 inf 특징
1) 전염성: inf에 어떤 숫자를 더하거나 곱해도 결과 inf
2) 통계 파괴자: 이게 제일 중요함
데이터에 inf가 단 하나라도 섞여 있으면, 해당 컬럼의 평균(mean) 또는 합계(sum)를 구했을 때 결과가 무조건 inf로 나옵니다.
분석 데이터가 통째로 망가짐
3. NaN vs Inf
| NaN | Inf | |
| 의미 | 데이터가 없음 (빈칸) | 숫자가 너무 커서 측정 불가 (무한대) |
| 발생 원인 | 데이터 누락, 잘못된 연산 (0/0) | 0으로 나누기, 지수 함수 폭발 등 |
| 데이타 타입 | 실수형(float) | 실수형(float) |
4. 실무적인 작업
판다스의 많은 기능(fillna, dropna 등)은 기본적으로 NaN을 기준으로 설계되어 있음. 그래서, inf를 NaN으로 먼저 바꿔놓아야 함.
그렇지 않으면 데이타가 망가짐
(실무예)
df = df.replace([np.inf, -np.inf, 'inf', '-inf'], np.nan)
"무한대(inf)라는 계산 불가능한 값들을 일단 '비어있는 칸(NaN)'으로 만들어버리자. 그러면 나중에 한꺼번에 0으로 채우든 지우든 처리하기 편하니까!"
오늘 그동안 우연히(?) 그것도 오랫동안 잘 동작하는 코드에 문제가 생겨서, 하루 종일 고생을 해서 내용을 정리함.
1. 기존방식: (\d{6})
pattern_a = re.compile(rf"{file_key}_(\d{6})_(\d{6})\.xlsx")
- 정상적으로 동작하다가 에러가 발생
- 에러: {6} 는 f-string 문법에서 "변수를 포맷팅할 때 쓰는 중괄호"로 인식 -> 그동안 어떻게 동작했지?
- 에러 원인: 추측하기로는 파이썬이 이걸 f-string의 포맷팅 구문으로 보려고 하다가, 6은 변수도 아니고 포맷 명세도 아닌데 그냥 "6"으로 인식해서 에러가 발생함(구글링을 해보니, 보통은 잘된다고 나옴 ㅠㅠㅠ)
- 해결 아래와 같이 안전한 방식으로 하는게 최고임
2. 개선방식: (\d{{6}})
pattern_b = re.compile(rf"{file_key}_(\d{{6}})_(\d{{6}})\.xlsx")
- {{ 와 }} 는 f-string에서 중괄호 이스케이프이기때문, f-string이 해석할 때 {{6}} → 문자열 "{6}" 으로 변환됨
- 안전한 방식으로 하자
3. 결론
- 정규식에 {n} 패턴을 쓸 때는 f-string 안에서는 반드시 {{n}} 로 써야함.
