1학년 / 2학기 / AI-R-PY / 3강

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는 표 형태 데이터를 다루는 파이썬 라이브러리다.

객체차원비유
Series1차원이름이 붙은 하나의 열
DataFrame2차원행과 열로 이루어진 표
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으로 숫자로 바꾼다.
  • 중복 제거와 결측치 대체는 실행 전에 분석 목적과 데이터 의미를 먼저 확인해야 한다.
오늘도 한 걸음 앞으로.

내용을 이해했다면 학습 완료를 체크해 주세요.

학습 기록은 현재 브라우저에 저장됩니다.
HJS / STUDY한지석