4주차: 파일 입출력과 Pandas 데이터 처리
이번 강의에서 배울 것
- 텍스트 파일을 안전하게 열고 읽고 쓸 수 있다.
- CSV·Excel 데이터를 Pandas DataFrame으로 불러오고 구조를 점검할 수 있다.
- loc와 iloc을 구분해 행과 열을 선택할 수 있다.
- 결측치·중복값을 처리하고 조건에 맞는 행을 필터링할 수 있다.
- 집계와 변환으로 데이터의 특징을 요약할 수 있다.
학습 경로
이전: 3주차 · 조건문, 반복문과 함수 · 다음: 보충 · Pandas 기본기능 총정리
범위: 4주차 슬라이드 3–29
단원 도입
| 핵심 포인트 | 중요도 | 이렇게 확인한다 |
|---|---|---|
파일 모드 r·w·a·x의 차이 | ★★★ | 기존 파일이 있을 때 w와 a의 결과 |
loc(끝 포함) vs iloc(끝 미포함) | ★★★ | 같은 슬라이스의 결과 행 수 비교 |
여러 조건 필터: 괄호 + &·|·~ | ★★★ | 틀린 필터 코드 고치기 |
dropna·fillna의 옵션 | ★★ | thresh=3의 뜻 쓰기 |
duplicated(keep=False) | ★★ | 중복 그룹 표시 방식 |
agg·transform·apply | ★ | 결과 모양 비교 |
형광펜 읽는 법: 노랑 핵심 정의·결론 · 빨강 헷갈리기 쉬운 구분·함정 · 파랑 외워야 할 순서·목록
PART 1 · 파일 입출력
파일 열기와 닫기
3p~4p
open()은 파일 객체를 반환한다. 모드에 따라 읽기·쓰기 동작이 달라진다.
| 모드 | 의미 | 파일이 없을 때 | 기존 내용 |
|---|---|---|---|
"r" | 읽기 (기본값) | 오류 (FileNotFoundError) | 유지 |
"w" | 쓰기 | 새로 생성 | 모두 지움 |
"a" | 이어 쓰기 | 새로 생성 | 뒤에 추가 |
"x" | 새 파일 만들기 | 새로 생성 | 이미 있으면 오류 |
파일은 with 문으로 여는 것이 안전하다. 블록을 벗어나면 오류가 생겨도 자동으로 닫힌다.
with open("test.txt", "w", encoding="utf-8") as file:
file.write("첫 번째 줄\n")
file.write("두 번째 줄\n")
file.write("세 번째 줄\n")
# 여기서 file은 이미 닫혀 있음파일 내용 읽기
5p~6p
with open("test.txt", "r", encoding="utf-8") as file:
first_four = file.read(4) # → '첫 번째' 네 글자
next_line = file.readline() # → ' 줄\n' 현재 위치부터 줄 끝까지
rest = file.read() # → '두 번째 줄\n세 번째 줄\n'| 메서드 | 반환 내용 |
|---|---|
read() | 남은 내용 전체 (문자열 하나) |
read(n) | 현재 위치에서 최대 n글자 |
readline() | 한 줄 |
readlines() | 각 줄을 요소로 갖는 리스트 |
for line in file: | 한 줄씩 차례로 (큰 파일에 적합) |
PART 2 · Pandas 시작
Pandas와 DataFrame
7p~8p
Pandas는 표 형태 데이터를 다루는 파이썬 라이브러리다.
| 객체 | 차원 | 비유 |
|---|---|---|
Series | 1차원 | 이름이 붙은 하나의 열 |
DataFrame | 2차원 | 행과 열로 이루어진 표 |
import pandas as pd관례적으로 Pandas를 pd라는 별칭으로 불러온다. 별칭은 필수가 아니지만 문서와 예제 대부분이 이 관례를 따른다. 그림으로 보는 Series·DataFrame·Index의 관계는 보충 · Pandas 기본기능에 정리했다.
CSV와 Excel 불러오기
9p~14p
import pandas as pd
csv_df = pd.read_csv("file1.csv")
excel_df = pd.read_excel("file1.xlsx")
print(csv_df.head()) # 처음 5행
print(csv_df.head(1)) # 처음 1행| 확인 방법 | 목적 |
|---|---|
df.head() | 앞부분의 값과 열 이름 빠르게 확인 |
df.shape | (행 개수, 열 개수) 확인 |
df.dtypes | 각 열의 자료형 확인 |
df.info() | 결측치와 메모리 사용량까지 요약 |
Series와 DataFrame 만들기
15p
names = ["Olga", "Andrew", "Brian", "Telulah", "Nicole", "Tilda"]
ages = [29, 21, 45, 23, 39, 46]
married = [False, True, True, True, False, True]
name_series = pd.Series(names, name="name")
people = pd.DataFrame({
"name": names,
"age": ages,
"married": married,
})
print(name_series.iloc[2]) # → Brian
print(people.iloc[2, 0]) # → Brian 2번 행, 0번 열인덱스와 표 구조 확인
16p~17p
CSV의 첫 열이 실제 행 이름이라면 불러올 때 인덱스로 지정할 수 있다.
nutrition = pd.read_csv("nutrition.csv", index_col=0)
print(nutrition.axes) # [행 인덱스, 열 인덱스]
print(nutrition.index) # 행 이름 (식품 이름)
print(nutrition.columns) # 열 이름 (영양소)
print(nutrition.sample(n=3, random_state=12))random_state를 고정하면 무작위 표본을 다시 실행해도 같은 결과가 나와 분석을 재현하기 쉽다(5주차 np.random.seed와 같은 목적).
불필요한 열은 명시적으로 제거한다.
nutrition = nutrition.drop(columns=["Unnamed: 0"], errors="ignore")PART 3 · 고르기
loc: 이름으로 선택하기
18p
loc는 행과 열의 레이블(이름)을 사용한다. 레이블 슬라이스는 끝 레이블도 포함한다.
row = nutrition.loc["Eggplant, raw"] # 행 하나 → Series
calories = nutrition.loc["Eggplant, raw", "calories"] # 값 하나
subset = nutrition.loc[
["Raspberries, raw", "Blackberries, raw"], # 행 목록
["protein", "vitamin_b6", "water"], # 열 목록
]iloc, at과 iat
19p
iloc은 0부터 시작하는 정수 위치로 선택한다. 파이썬 슬라이스처럼 끝 위치를 포함하지 않는다.
first_row = nutrition.iloc[0] # 첫 번째 행
selected = nutrition.iloc[[4, 6, 9], 2:5] # 4·6·9번 행 × 2·3·4번 열| 접근자 | 기준 | 슬라이스 끝 | 용도 |
|---|---|---|---|
loc | 레이블 | 포함 | 여러 행·열, 조건 선택 |
iloc | 정수 위치 | 미포함 | 여러 행·열, 위치 선택 |
at | 레이블 | — | 단일 값 빠르게 접근 |
iat | 정수 위치 | — | 단일 값 빠르게 접근 |
value_by_label = nutrition.at["Nuts, pecans", "calories"]
value_by_position = nutrition.iat[1, 1]PART 4 · 다듬기
자료형 변환
20p
people = pd.DataFrame({
"age": [12, 13, 14, 16],
"weight": [41.1, 34.5, 83.2, 90.1],
"height": ["1.72", "1.74", "1.91", "1.54"], # 숫자처럼 보이는 문자열
})
people["height"] = people["height"].astype(float)
people["age"] = people["age"].astype(int)결측치 처리와 정렬
21p
결측치는 정보가 비어 있음을 나타내며 흔히 NaN(Not a Number)으로 표현된다.
| 코드 | 의미 |
|---|---|
df.isna() | 각 값의 결측 여부 (True/False 표) |
df.isna().sum() | 열별 결측치 개수 |
df.dropna() | 결측치가 하나라도 있는 행 제거 |
df.dropna(how="all") | 모든 값이 결측인 행만 제거 |
df.dropna(thresh=3) | 정상 값이 3개 이상인 행만 유지 |
df.fillna(value) | 결측치를 지정 값으로 채움 |
sorted_nutrition = nutrition.sort_values(
by=["cholesterol", "sodium"],
ascending=[False, True], # 콜레스테롤 내림차순 → 같으면 나트륨 오름차순
)불리언 조건으로 행 필터링
22p~25p
valuable = players.loc[players["market_value"] > 40]
defenders = players.loc[players["position"].isin(["LB", "CB", "RB"])]
young = players.loc[players["age"] <= 25]
mid_value = players.loc[players["market_value"].between(40, 50)] # 40 이상 50 이하여러 조건은 &(그리고), |(또는), ~(부정)로 결합하고 각 비교식을 괄호로 감싼다.
target = players.loc[
(players["position"] == "LB")
& (players["age"] <= 25)
& (players["market_value"] >= 10)
& ~players["club"].isin(["Tottenham", "Arsenal"])
]중복 행 찾기와 제거
26p
key_columns = ["club", "age", "position", "market_value"]
duplicates = players.loc[
players.duplicated(subset=key_columns, keep=False) # 중복 그룹의 모든 행 표시
]
deduplicated = players.drop_duplicates(
subset=key_columns,
keep="first", # 그룹에서 첫 행만 남김
)keep= | duplicated()가 True로 표시하는 행 |
|---|---|
"first" (기본값) | 첫 번째를 뺀 나머지 중복 |
"last" | 마지막을 뺀 나머지 중복 |
False | 중복 그룹의 모든 행 |
keep=False는 중복 그룹의 모든 행을 표시하므로 조사에 유용하다. 중복 제거 전에는 어떤 열의 조합을 동일 관측치의 기준으로 볼지 먼저 정해야 한다.
결측치 대체
27p
players = players.fillna({
"market_value": players["market_value"].mean(), # 수치형: 평균
"position": "RM", # 범주형: 지정 값
})집계와 변환
28p~29p
summary = (
players.select_dtypes(include="number") # 숫자 열만
.agg(["min", "max", "mean"]) # 열마다 세 가지 요약
)
converted = players[["market_value", "fpl_value"]] * 0.91 # 열 전체에 한 번에 곱하기| 메서드 | 역할 | 결과의 관점 |
|---|---|---|
agg() | 여러 값을 하나의 요약값으로 축약 | 열별 최솟값·평균 등 |
transform() | 각 입력 위치에 대응하는 값을 반환 | 원본과 같은 모양 유지 |
apply() | 함수를 행 또는 열 단위로 적용 | 함수에 따라 달라짐 |
def round_float_series(series):
if pd.api.types.is_float_dtype(series):
return series.round()
return series
rounded = players.apply(round_float_series) # 열마다 함수 적용정답과 해설
1. "w"는 기존 내용을 지우고 새 줄 하나만 남기고, "a"는 기존 내용 뒤에 새 줄을 덧붙인다.
2. loc[2:5]는 끝 포함 → 4행(2, 3, 4, 5), iloc[2:5]는 끝 미포함 → 3행(2, 3, 4).
3. df[(df["age"] > 20) & (df["club"] == "Arsenal")]. and 대신 &를 쓰고 각 비교식을 괄호로 감싼다.
4. 결측이 아닌 값이 3개 이상인 행만 남긴다.
플래시카드
4주차 — 파일 모드 r, w, a, x의 차이는?
r는 읽기(없으면 오류), w는 쓰기(기존 내용 삭제), a는 이어 쓰기(뒤에 추가), x는 새 파일 만들기(이미 있으면 오류).
4주차 — 파일을 with 문으로 여는 이유는?
블록을 벗어나면 오류가 생겨도 자동으로 닫히기 때문. close()를 빠뜨릴 걱정이 없다.
4주차 — read(), readline(), readlines()의 차이는?
남은 전체를 문자열 하나로, 한 줄만, 모든 줄을 리스트로. 파일 객체는 읽은 위치를 기억하며 seek(0)으로 처음으로 돌아간다.
4주차 — 데이터를 불러온 직후 확인할 세 가지는?
head()로 값과 열 이름, shape로 크기, info()로 자료형과 결측치.
4주차 — loc와 iloc의 차이는?
loc는 레이블(이름) 기준이고 슬라이스 끝을 포함한다. iloc은 정수 위치 기준이고 끝을 포함하지 않는다. 단일 값은 at, iat.
4주차 — Pandas 조건을 여러 개 결합하는 규칙은?
각 비교식을 괄호로 감싸고 and/or/not 대신 &, |, ~를 쓴다.
4주차 — duplicated(keep=False)는 무엇을 표시하는가?
중복 그룹의 모든 행을 True로 표시한다. 기본값 keep="first"는 첫 행을 뺀 나머지만 표시한다.
4주차 — agg, transform, apply의 차이는?
agg는 여러 값을 요약값 하나로 줄이고, transform은 원본과 같은 모양을 유지하며, apply는 함수를 행 또는 열 단위로 적용한다.
핵심 점검
- 파일을 자동으로 닫는 안전한 문법은 이다.
"w"모드는 기존 내용을 .DataFrame의 크기는 로 확인한다.loc는 ,iloc은 를 기준으로 선택한다.- Pandas 조건을 결합할 때는 각 조건을 로 감싸고
&,|,~를 사용한다. - 숫자처럼 보이는 문자열 열은 또는
pd.to_numeric으로 숫자로 바꾼다. - 중복 제거와 결측치 대체는 실행 전에 분석 목적과 데이터 의미를 먼저 확인해야 한다.
내용을 이해했다면 학습 완료를 체크해 주세요.