defaultdict와 딕셔너리 응용 코드

"밑바닥부터 시작하는 데이터 과학"의 챕터 1에서 발췌 및 수정.
이해하기 쉬운 문제들 일부 추출하고, 일부는 새롭게 구성.
구글에서 "id": 0, "name": "Hero" 검색하면 소스코드로 바로 이동할 수 있다.


아래 코드는 뒤에서 제안할 문제에서 사용하는 데이터 정의.
이번 코드를 통해 dict 클래스 확장판인 defaultdict 클래스에 대해 알게 되면 좋겠다.

users = [
{ "id": 0, "name": "Hero" },
{ "id": 1, "name": "Dunn" },
{ "id": 2, "name": "Sue" },
{ "id": 3, "name": "Chi" },
{ "id": 4, "name": "Thor" },
{ "id": 5, "name": "Clive" },
{ "id": 6, "name": "Hicks" },
{ "id": 7, "name": "Devin" },
{ "id": 8, "name": "Kate" },
{ "id": 9, "name": "Klein" },
{ "id": 10, "name": "Jen" }
]

friendships = [(0, 1), (0, 2), (1, 2), (1, 3), (2, 3), (3, 4),
(4, 5), (5, 6), (5, 7), (6, 8), (7, 8), (8, 9)]

interests = [
(0, "Hadoop"), (0, "Big Data"), (0, "HBase"), (0, "Java"),
(0, "Spark"), (0, "Storm"), (0, "Cassandra"),
(1, "NoSQL"), (1, "MongoDB"), (1, "Cassandra"), (1, "HBase"),
(1, "Postgres"), (2, "Python"), (2, "scikit-learn"), (2, "scipy"),
(2, "numpy"), (2, "statsmodels"), (2, "pandas"), (3, "R"), (3, "Python"),
(3, "statistics"), (3, "regression"), (3, "probability"),
(4, "machine learning"), (4, "regression"), (4, "decision trees"),
(4, "libsvm"), (5, "Python"), (5, "R"), (5, "Java"), (5, "C++"),
(5, "Haskell"), (5, "programming languages"), (6, "statistics"),
(6, "probability"), (6, "mathematics"), (6, "theory"),
(7, "machine learning"), (7, "scikit-learn"), (7, "Mahout"),
(7, "neural networks"), (8, "neural networks"), (8, "deep learning"),
(8, "Big Data"), (8, "artificial intelligence"), (9, "Hadoop"),
(9, "Java"), (9, "MapReduce"), (9, "Big Data")
]

# 근속연수에 대한 연봉 : 사용하지 않는 데이터
salaries_and_tenures = [(83000, 8.7), (88000, 8.1),
(48000, 0.7), (76000, 6),
(69000, 6.5), (76000, 7.5),
(60000, 2.5), (83000, 10),
(48000, 1.9), (63000, 4.2)]


[문제 1번] users에 각각의 회원들에 대한 친구 필드를 추가하세요.

from collections import defaultdict

def find_member(users, member_id):
for u in users:
if u['id'] == member_id:
return u
return None


for u in users:
u['friend'] = []

# for i, j in friendships: # id가 순서를 보장할 수 없다면,
# u1 = find_member(users, i)
# u2 = find_member(users, j)
#
# u1['friend'].append(j)
# u2['friend'].append(i)

for i, j in friendships: # id가 순서를 보장한다면,
users[i]['friend'].append(j)
users[j]['friend'].append(i)

print(*users, sep='\n')
print('-'*50)

# [출력 결과]
# {'friend': [1, 2], 'id': 0, 'name': 'Hero'}
# {'friend': [0, 2, 3], 'id': 1, 'name': 'Dunn'}
# {'friend': [0, 1, 3], 'id': 2, 'name': 'Sue'}
# {'friend': [1, 2, 4], 'id': 3, 'name': 'Chi'}
# {'friend': [3, 5], 'id': 4, 'name': 'Thor'}
# {'friend': [4, 6, 7], 'id': 5, 'name': 'Clive'}
# {'friend': [5, 8], 'id': 6, 'name': 'Hicks'}
# {'friend': [5, 8], 'id': 7, 'name': 'Devin'}
# {'friend': [6, 7, 9], 'id': 8, 'name': 'Kate'}
# {'friend': [8], 'id': 9, 'name': 'Klein'}
# {'friend': [], 'id': 10, 'name': 'Jen'}


[문제 2] 친구가 가장 많은 사람과 적은 사람을 출력하세요.

users_by_friends = sorted(users, key=lambda d: len(d['friend']), reverse=True)
print(users[0])
print(users[-1])
print('.'*50)
print(*users_by_friends, sep='\n')
print('-'*50)

# [출력 결과]
# {'friend': [1, 2], 'id': 0, 'name': 'Hero'}
# {'friend': [], 'id': 10, 'name': 'Jen'}
# ..................................................
# {'friend': [0, 2, 3], 'id': 1, 'name': 'Dunn'}
# {'friend': [0, 1, 3], 'id': 2, 'name': 'Sue'}
# {'friend': [1, 2, 4], 'id': 3, 'name': 'Chi'}
# {'friend': [4, 6, 7], 'id': 5, 'name': 'Clive'}
# {'friend': [6, 7, 9], 'id': 8, 'name': 'Kate'}
# {'friend': [1, 2], 'id': 0, 'name': 'Hero'}
# {'friend': [3, 5], 'id': 4, 'name': 'Thor'}
# {'friend': [5, 8], 'id': 6, 'name': 'Hicks'}
# {'friend': [5, 8], 'id': 7, 'name': 'Devin'}
# {'friend': [8], 'id': 9, 'name': 'Klein'}
# {'friend': [], 'id': 10, 'name': 'Jen'}


[문제 3] 친구가 한 명도 없는 사람들을 출력하세요.

no_friend = [d for d in users if not d['friend']]
print(*no_friend, sep='\n')
print('-'*50)

# [출력 결과]
# {'friend': [], 'id': 10, 'name': 'Jen'}


[문제 4] 친구가 3명 이상인 사람들을 출력하세요.

more_3 = [d for d in users if len(d['friend']) >= 3]
print(*more_3, sep='\n')
print('-'*50)

# [출력 결과]
# {'friend': [0, 2, 3], 'id': 1, 'name': 'Dunn'}
# {'friend': [0, 1, 3], 'id': 2, 'name': 'Sue'}
# {'friend': [1, 2, 4], 'id': 3, 'name': 'Chi'}
# {'friend': [4, 6, 7], 'id': 5, 'name': 'Clive'}
# {'friend': [6, 7, 9], 'id': 8, 'name': 'Kate'}


[문제 5] 회원이 관심 갖는 주제들을 출력하세요.

def find_interest_by_member(interests, member_id):
finds = []
for m_id, interest in interests:
if m_id == member_id:
finds.append(interest)

return finds

print(find_interest_by_member(interests, 1))

users_by_member = defaultdict(list)
for m_id, interest in interests:
users_by_member[m_id].append(interest)

# print(*users_by_member.items(), sep='\n')
print(users_by_member[1])
print('-'*50)

# [출력 결과]
# ['NoSQL', 'MongoDB', 'Cassandra', 'HBase', 'Postgres']
# ['NoSQL', 'MongoDB', 'Cassandra', 'HBase', 'Postgres']


[문제 6] hadoop에 관심 있는 사람들을 출력하세요.

def find_members_by_interest(interests, word):
finds = []
for m_id, interest in interests:
if interest == word:
finds.append(m_id)

return finds

print(find_members_by_interest(interests, 'Hadoop'))

interest_users = defaultdict(list)
for m_id, interest in interests:
interest_users[interest].append(m_id)

# print(*interest_users.items(), sep='\n')
print(interest_users['Hadoop'])
print('-'*50)

# [출력 결과]
# [0, 9]
# [0, 9]


[문제 7] 가장 많은 관심을 갖는 주제 3가지를 출력하세요.

from collections import Counter
from operator import itemgetter

c = defaultdict(int)
for _, word in interests:
c[word] += 1

# c = Counter([word for _, word in interests])
c = sorted(c.items(), key=itemgetter(1))
print(c[:-4:-1])
print(c[::-1])

# [출력 결과]
# [('Python', 3), ('Java', 3), ('Big Data', 3)]
# [('Python', 3), ('Java', 3), ('Big Data', 3), ('R', 2), <이하 생략>

'파이썬' 카테고리의 다른 글

enum 클래스  (0) 2017.04.09
구조체로 사용할 수 있는 collections.namedtuple  (0) 2017.04.09
defaultdict 사용법  (0) 2017.04.06
정규분포와 누적분포 비교 그래프  (0) 2017.04.06
matplotlib colormap  (0) 2017.04.05