R 리스트(List) 구조 한 방에 이해하기

지금까지 배운 R의 기본 1차원 벡터(Vector)는 반드시 태생부터 “단일 타입(예: 모두 숫자이거나 모두 문자만 허용)”으로만 강제로 묶여야 한다는 답답함이 있었습니다. 그러나 우리가 처리할 현실 세계의 데이터는 절대 그렇지 않죠. “이름상자(문자), 회원번호상자(숫자), 구매이력이나 장바구니 내역 모음(또 다른 벡터 형태)” 등 서로 전혀 다른 온갖 복잡한 유형의 정보들을 하나의 거대한 개인별 쇼핑 바구니에 전부 넣고 들고 다녀야 할 때가 무조건 찾아옵니다.

이럴 때 사용하는 R의 궁극적이고 이질적인 데이터 컨테이너가 바로 리스트(List)입니다. 리스트는 R 데이터 구조의 궁극적 종착역이자, 데이터 프레임을 만들기 위한 뼈대(핵심 엔진)입니다. 이 포스트 하나로 완벽히 리스트를 이해해 봅시다!

1. 모든 이질적인 것을 다 담아내는 마법의 바구니, list()

동일한 녀석들만 모으던 벡터가 c()로 묶였다면, 다양한 것을 한 번에 품는 리스트는 list()라는 전용 결합 함수로 생성합니다.

mylist <- list(
    name = "issac",          # 문자 데이터 달랑 한 개
    id = 30096,              # 숫자 데이터 한 개
    order = c(1, 2)          # 길이가 2개인 또 다른 벡터 집합
)

mylist
> $name
> [1] "issac"
> 
> $id
> [1] 30096
> 
> $order
> [1] 1 2

생성 후 곧바로 콘솔에 출력해 보면, 놀랍게도 각각 지어진 방($name, $id, $order)에 각기 다른 형태(문자/숫자)와 심지어 길이(데이터 수량이 1개/2개)가 다름에도 에러 없이 너무나 평화롭게 공존하고 있는 것을 생생하게 보실 수 있습니다. 이게 만약 기존의 c() 구조였다면 전부 강제로 문자로 역변환되어버리거나 충돌 강제 종료 에러가 났을 일입니다.

2. 리스트 방 문을 여는 3가지 마스터키 (인덱싱 권법)

리스트 안에 보관된 세부 데이터들만 입맛에 맞게 정교히 접근하려면 크게 세 가지 열쇠를 나눠 쓸 수 있습니다. 초보 시절엔 이 부분이 구분이 안 가 가장 헷갈리지만 매우 중요한 기본기입니다.

① 가장 직관적인 $ (달러) 기호 열쇠 사용하기

앞서 생성했던 것처럼 각 칸마다 태그(이름표)가 견고히 붙은 Named 리스트라면, 달러 기호($)를 통해 다이렉트로 그 방의 철문을 열고 접근할 수 있습니다. 거의 90% 이상 엑셀 열 데이터 접근에 쓰이는 방식입니다.

mylist$name
> [1] "issac"
mylist$order
> [1] 1 2

② 리스트 방 번호로 직접 내부 침투 [[]] (이중 대괄호)

만약 너무 데이터가 방대해 태그이름을 다 기억하지 못하지만, 이게 첫 번째 방이라는 방 번호(순서)를 정확히 안다면? 이중 대괄호 [[ ]] 안에 숫자를 넣어 해당 원소 알맹이(본질) 그 자체의 데이터형으로 끄집어냅니다.

mylist[[1]]
> [1] "issac"

③ 리스트 포장 상태 그대로 배달받기 [] (단일 대괄호)

아주 헷갈리실 수 있는데, 이중 대괄호 [[]]가 택배 상자의 포장을 북북 찢어 까서 알맹이만 쏙 빼내는 거라면, 겉의 단일 대괄호 []는 내용물은 건들지 않고 상자(리스트 속성)는 여전히 포장된 상태로 부분집합만 잘라서 가져옵니다.

mylist["name"]
> $name
> [1] "issac"

결과물 최상단에 $name이라는 라벨이 안 풀리고 그대로 딸려오는 것이 보이시나요? 즉, 이것의 정체는 방 1개짜리 ‘미니 리스트’가 반환된 것입니다.

💡 핵심 메모리아 요약: [[]] vs [] 의 결정적 차이
[[]] : 껍질을 까서 내용물(원소) 그 자체를 가져옴 (문자면 문자로 반환).
[] : 껍질(리스트 상태 구조)을 무조건 유지한 채 바구니만 작게 잘라옴.

3. 리스트 방 수정 및 과감하게 삭제하기

데이터 전처리 중 새로운 속성(열)을 집어 넣거나 필요 없어진 빅테이터 기록 찌꺼기를 지울 때도 마치 변수에 값을 넣듯 $만 쓰면 다이렉트 처리가 됩니다.

# 새로운 방 이름(연락처 폰번호) 기재하여 추가 런칭!
mylist$phone <- "010-0000-0000"

# 기존 방(아이디) 내용을 최신 내역으로 덮어 바꾸기!
mylist$id <- 99999

# 불필요해진 방 자체를 통째로 폭파시켜 지우기! (NULL 사용)
mylist$order <- NULL

4. 너무 복잡한 놈들을 단숨에 펴버리기 전략: unlist()

웹 시스템과 API 연결을 통해 돌려받은 초거대 리스트 구조(예: JSON 포맷)가 너무 복잡해서 속이 터질 떄가 있습니다. 어차피 안에 등재된 건 숫자나 문자열 뿐이니 그냥 일렬로 된 평평한 단순 벡터(Vector)로 전부 다 평평하게 펴버리고 싶을 때가 있습니다.

unlist(mylist)
>           name             id          phone 
>        "issac"        "99999" "010-0000-0000"

이 마법의 unlist() 함수 한 방이면 아무리 겹겹이 계층형으로 쌓인 수천 겹 박스들도 단번에 분해해서 1차원의 쫙 펴진, 엑셀 1열 같은 단순한 데이터 형태로 만들어줍니다. (웹 브라우저 크롤링 원시 데이터나 복잡한 LLM API 결과값을 정리할 때 완전 구세주 역할을 합니다!)


여러분이 RStudio나 Positron에서 만나는 모든 데이터프레임과 시계열 모델링 통계 결과물 리포트는 사실 다 이 리스트(List) 뼈대 구조로 되어 있습니다. 오늘 배운 $ 연산자와 [[]] 까내기 권법을 온몸으로 기억하신다면 앞으로 R 에러 메시지 분석에서 막혀 좌절하실 일은 단언컨대 없습니다!


당신이 좋아할 만한 콘텐츠

by Google Adsense


관련 글 보기