아이템 처리를 위한 리스트 컴프리헨션

Beginner

This tutorial is from open-source community. Access the source code

소개

일반적인 작업은 목록의 항목을 처리하는 것입니다. 이 섹션에서는 바로 그 작업을 수행하기 위한 강력한 도구인 리스트 컴프리헨션 (list comprehensions) 을 소개합니다.

이것은 가이드 실험입니다. 학습과 실습을 돕기 위한 단계별 지침을 제공합니다.각 단계를 완료하고 실무 경험을 쌓기 위해 지침을 주의 깊게 따르세요. 과거 데이터에 따르면, 이것은 초급 레벨의 실험이며 완료율은 91%입니다.학습자들로부터 100%의 긍정적인 리뷰율을 받았습니다.

새로운 리스트 생성

리스트 컴프리헨션은 시퀀스의 각 요소에 연산을 적용하여 새로운 리스트를 생성합니다.

>>> a = [1, 2, 3, 4, 5]
>>> b = [2*x for x in a ]
>>> b
[2, 4, 6, 8, 10]
>>>

또 다른 예시:

>>> names = ['Elwood', 'Jake']
>>> a = [name.lower() for name in names]
>>> a
['elwood', 'jake']
>>>

일반적인 구문은 다음과 같습니다: [ <expression> for <variable_name> in <sequence> ].

필터링

리스트 컴프리헨션 동안 필터링도 할 수 있습니다.

>>> a = [1, -5, 4, 2, -2, 10]
>>> b = [2*x for x in a if x > 0 ]
>>> b
[2, 8, 4, 20]
>>>

사용 사례

리스트 컴프리헨션은 매우 유용합니다. 예를 들어, 특정 딕셔너리 필드의 값을 수집할 수 있습니다.

stocknames = [s['name'] for s in stocks]

시퀀스에 대해 데이터베이스와 유사한 쿼리를 수행할 수 있습니다.

a = [s for s in stocks if s['price'] > 100 and s['shares'] > 50 ]

또한 리스트 컴프리헨션과 시퀀스 축약을 결합할 수 있습니다.

cost = sum([s['shares']*s['price'] for s in stocks])

일반적인 구문 (General Syntax)

[ <expression> for <variable_name> in <sequence> if <condition>]

의미:

result = []
for variable_name in sequence:
    if condition:
        result.append(expression)

역사적 변천 (Historical Digression)

리스트 컴프리헨션은 수학에서 유래되었습니다 (집합 - 구성 표기법).

a = [ x * x for x in s if x > 0 ] ## Python

a = { x^2 | x ∈ s, x > 0 }         ## Math

또한 다른 여러 언어에서도 구현되었습니다. 대부분의 코더는 아마도 수학 수업을 생각하지 않을 것입니다. 따라서, 이것을 멋진 리스트 단축키로 보는 것도 괜찮습니다.

연습 문제 2.19: 리스트 컴프리헨션 (List comprehensions)

구문에 익숙해지기 위해 몇 가지 간단한 리스트 컴프리헨션을 시도해 보세요.

>>> nums = [1,2,3,4]
>>> squares = [ x * x for x in nums ]
>>> squares
[1, 4, 9, 16]
>>> twice = [ 2 * x for x in nums if x > 2 ]
>>> twice
[6, 8]
>>>

리스트 컴프리헨션이 데이터를 적절하게 변환하거나 필터링하여 새로운 리스트를 생성하는 방식을 확인하세요.

연습 문제 2.20: 시퀀스 축약 (Sequence Reductions)

단일 Python 문을 사용하여 포트폴리오의 총 비용을 계산합니다.

>>> portfolio = read_portfolio('portfolio.csv')
>>> cost = sum([ s['shares'] * s['price'] for s in portfolio ])
>>> cost
44671.15
>>>

그 후, 단일 문을 사용하여 포트폴리오의 현재 가치를 계산하는 방법을 보여주세요.

>>> value = sum([ s['shares'] * prices[s['name']] for s in portfolio ])
>>> value
28686.1
>>>

위의 두 연산 모두 맵 - 리덕션 (map-reduction) 의 예입니다. 리스트 컴프리헨션은 리스트 전체에 연산을 매핑합니다.

>>> [ s['shares'] * s['price'] for s in portfolio ]
[3220.0000000000005, 4555.0, 12516.0, 10246.0, 3835.1499999999996, 3254.9999999999995, 7044.0]
>>>

그런 다음 sum() 함수는 결과에 대한 축약 (reduction) 을 수행합니다.

>>> sum(_)
44671.15
>>>

이 지식을 바탕으로 이제 빅데이터 스타트업 회사를 시작할 준비가 되었습니다.

연습 문제 2.21: 데이터 쿼리 (Data Queries)

다양한 데이터 쿼리의 다음 예제를 시도해 보세요.

먼저, 100 주 이상 보유한 모든 포트폴리오 보유 목록입니다.

>>> more100 = [ s for s in portfolio if s['shares'] > 100 ]
>>> more100
[{'price': 83.44, 'name': 'CAT', 'shares': 150}, {'price': 51.23, 'name': 'MSFT', 'shares': 200}]
>>>

MSFT 및 IBM 주식에 대한 모든 포트폴리오 보유 목록입니다.

>>> msftibm = [ s for s in portfolio if s['name'] in {'MSFT','IBM'} ]
>>> msftibm
[{'price': 91.1, 'name': 'IBM', 'shares': 50}, {'price': 51.23, 'name': 'MSFT', 'shares': 200},
  {'price': 65.1, 'name': 'MSFT', 'shares': 50}, {'price': 70.44, 'name': 'IBM', 'shares': 100}]
>>>

10,000 달러 이상 비용이 드는 모든 포트폴리오 보유 목록입니다.

>>> cost10k = [ s for s in portfolio if s['shares'] * s['price'] > 10000 ]
>>> cost10k
[{'price': 83.44, 'name': 'CAT', 'shares': 150}, {'price': 51.23, 'name': 'MSFT', 'shares': 200}]
>>>

연습 문제 2.22: 데이터 추출 (Data Extraction)

namesharesportfolio에서 가져온 튜플 (name, shares)의 목록을 어떻게 만들 수 있는지 보여주세요.

>>> name_shares =[ (s['name'], s['shares']) for s in portfolio ]
>>> name_shares
[('AA', 100), ('IBM', 50), ('CAT', 150), ('MSFT', 200), ('GE', 95), ('MSFT', 50), ('IBM', 100)]
>>>

대괄호 ([,]) 를 중괄호 ({, }) 로 변경하면 집합 컴프리헨션 (set comprehension) 이라고 하는 것을 얻게 됩니다. 이는 고유하거나 구별되는 값을 제공합니다.

예를 들어, 이것은 portfolio에 나타나는 고유한 주식 이름의 집합을 결정합니다.

>>> names = { s['name'] for s in portfolio }
>>> names
{ 'AA', 'GE', 'IBM', 'MSFT', 'CAT' }
>>>

key:value 쌍을 지정하면 딕셔너리를 만들 수 있습니다. 예를 들어, 주식 이름을 보유한 총 주식 수에 매핑하는 딕셔너리를 만듭니다.

>>> holdings = { name: 0 for name in names }
>>> holdings
{'AA': 0, 'GE': 0, 'IBM': 0, 'MSFT': 0, 'CAT': 0}
>>>

이 후자의 기능은 **딕셔너리 컴프리헨션 (dictionary comprehension)**이라고 합니다. 표로 정리해 보겠습니다.

>>> for s in portfolio:
        holdings[s['name']] += s['shares']

>>> holdings
{ 'AA': 100, 'GE': 95, 'IBM': 150, 'MSFT':250, 'CAT': 150 }
>>>

prices 딕셔너리를 포트폴리오에 나타나는 이름만으로 필터링하는 이 예제를 시도해 보세요.

>>> portfolio_prices = { name: prices[name] for name in names }
>>> portfolio_prices
{'AA': 9.22, 'GE': 13.48, 'IBM': 106.28, 'MSFT': 20.89, 'CAT': 35.46}
>>>

연습 문제 2.23: CSV 파일에서 데이터 추출

리스트, 집합 및 딕셔너리 컴프리헨션 (list, set, and dictionary comprehensions) 의 다양한 조합을 사용하는 방법을 아는 것은 다양한 형태의 데이터 처리에 유용할 수 있습니다. 다음은 CSV 파일에서 선택한 열을 추출하는 방법을 보여주는 예제입니다.

먼저, CSV 파일에서 헤더 정보 행을 읽습니다.

>>> import csv
>>> f = open('portfoliodate.csv')
>>> rows = csv.reader(f)
>>> headers = next(rows)
>>> headers
['name', 'date', 'time', 'shares', 'price']
>>>

다음으로, 실제로 관심 있는 열을 나열하는 변수를 정의합니다.

>>> select = ['name', 'shares', 'price']
>>>

이제 소스 CSV 파일에서 위의 열의 인덱스를 찾습니다.

>>> indices = [ headers.index(colname) for colname in select ]
>>> indices
[0, 3, 4]
>>>

마지막으로, 데이터 행을 읽고 딕셔너리 컴프리헨션을 사용하여 딕셔너리로 변환합니다.

>>> row = next(rows)
>>> record = { colname: row[index] for colname, index in zip(select, indices) }   ## dict-comprehension
>>> record
{'price': '32.20', 'name': 'AA', 'shares': '100'}
>>>

방금 일어난 일에 익숙하다면, 파일의 나머지 부분을 읽으세요.

>>> portfolio = [ { colname: row[index] for colname, index in zip(select, indices) } for row in rows ]
>>> portfolio
[{'price': '91.10', 'name': 'IBM', 'shares': '50'}, {'price': '83.44', 'name': 'CAT', 'shares': '150'},
  {'price': '51.23', 'name': 'MSFT', 'shares': '200'}, {'price': '40.37', 'name': 'GE', 'shares': '95'},
  {'price': '65.10', 'name': 'MSFT', 'shares': '50'}, {'price': '70.44', 'name': 'IBM', 'shares': '100'}]
>>>

맙소사, read_portfolio() 함수의 많은 부분을 단일 문장으로 줄였습니다.

해설 (Commentary)

리스트 컴프리헨션 (list comprehensions) 은 데이터를 변환, 필터링 또는 수집하는 효율적인 수단으로 파이썬에서 일반적으로 사용됩니다. 구문 때문에 과도하게 사용하지 않도록 주의하고, 각 리스트 컴프리헨션을 가능한 한 간단하게 유지하려고 노력해야 합니다. 여러 단계로 나누는 것도 괜찮습니다. 예를 들어, 마지막 예제를 예상치 못한 동료들에게 갑자기 보여주는 것은 명확하지 않을 수 있습니다.

그렇긴 하지만, 데이터를 빠르게 조작하는 방법을 아는 것은 매우 유용한 기술입니다. 데이터 가져오기, 내보내기, 추출 등과 관련된 일회성 문제를 해결해야 하는 상황이 많이 있습니다. 리스트 컴프리헨션의 전문가가 되면 솔루션을 고안하는 데 소요되는 시간을 상당히 줄일 수 있습니다. 또한, collections 모듈도 잊지 마세요.

요약 (Summary)

축하합니다! 리스트 컴프리헨션 랩을 완료했습니다. LabEx 에서 더 많은 랩을 연습하여 실력을 향상시킬 수 있습니다.