이번 포스팅은 쉬어가는 코너로, 

 

  - if~ elif~ else~ 조건절을 사용한 프로그래밍

  - for loop 순환문을 사용한 프로그래밍 

 

에 대한 간단한 예제 몇 가지를 소개하겠습니다. 

 

(1) 홀수, 짝수 여부 판별하기 (odd vs. even number)

(2) 소수 여부 판별하기 (prime number)

(3) 팩토리얼 계산하기 (factorial)

(4) 3&5, 3, 5 로 나누어지는 수 판별하기 (FizzBuzz)

(5) 1 ~5를 라인별로 1부터 시작해서 라인 개수 만큼 출력하기

(6) 1~15를 라인별로 라인 번호부터 시작해서 라인개수 만큼 출력하기

 

 

(1) 홀수, 짝수 여부 판별하기 (odd vs. even number)

 

## odd or even number
num = int(input("Enter a number: "))

if (num % 2) == 0:
    print("{num} is Even")
else:
    print("{num} is Odd")

# Enter a number: 6
# 6 is Even

 

 

 

(2) 소수 여부 판별하기 (prime number)

 

소수(the prime number)는 '1과 자기 자신 외의 약수를 가지지 않는 1보다 큰 자연수'를 말합니다. 

 

## Prime number or not
num = int(input("Enter a number: "))

prime_num = True
if num > 1:
    for i in range(2, num):
        if (num % i) == 0 :
            prime_num = False
            break

if prime_num == False:
    print(f"{num} is not a prime number.")
else:
    print(f"{num} is a prime number.")

# Enter a number: 47
# 47 is a prime number.

 

 

 

(3) 팩토리얼 계산하기 (factorial)

 

팩토리얼이란 어떤 양의 정수 n에 대해서, n부터 1까지의 모든 양의 정수를 곱한 값을 말합니다. 보통 "n!"로 표기하며, 팩토리얼은 수학적 계산과 조합론에서 중요한 개념입니다. 예를 들어, 5!는 5 x 4 x 3 x 2 x 1 = 120입니다. 팩토리얼은 주로 순열과 조합을 계산하거나 확률과 통계에서 사용됩니다.

 

## Factorial
num = int(input("Enter a number: "))

factorial = 1
if num < 0:
    print("Factorial does not exist for negative numbers.")
elif num == 0:
    print("The factorial of 0 is 1.")
else:
    for i in range(1, num + 1):
        factorial = factorial * i
    print(f"The factorial of {num} is {factorial}")

# Enter a number: 4
# The factorial of 4 is 24

 

 

 

(4) 3&5, 3, 5 로 나누어지는 수 판별하기 (FizzBuzz)

 

Python coding test 에 나올 법한 문제로 FizzBuzz 문제가 있습니다. 1보다 큰 양의 정수를 3과 5로 모두 나누어지면 "FizzBuzz", 3으로만 나누어지면 "Fizz", 5로만 나누어지면 "Buzz"라고 결과를 출력하는 문제입니다. 

 

# FizzBuzz Problem
# Fizz and Buzz refer to any number that is a multiple of 3 and 5
for i in range(1, 20):
    if i % 3 == 0 and i % 5 == 0:
        print("FizzBuzz")
    elif i % 3 == 0:
        print("Fizz")
    elif i % 5 == 0:
        print("Buzz")
    else:
        print(i)
        
# 1
# 2
# Fizz
# 4
# Buzz
# Fizz
# 7
# 8
# Fizz
# Buzz
# 11
# Fizz
# 13
# 14
# FizzBuzz
# 16
# 17
# Fizz
# 19

 

 

 

(5) 1 ~5를 라인별로 1부터 시작해서 라인 개수 만큼 출력하기

 

def num(n):
    for i in range(0, n):
        num = 1
        for j in range(0, i+1):
            print(num, end=" ")
            num += 1
        print("\r")
        
        
num(5)
# 1
# 1 2
# 1 2 3
# 1 2 3 4
# 1 2 3 4 5

 

 

 

(6) 1~15를 라인별로 라인 번호부터 시작해서 라인개수 만큼 출력하기

 

def num(n):
    num = 1
    for i in range(0, n):
        for j in range(0, i+1):
            print(num, end=" ")
            num += 1
        print("\r") # the first position of a line
        

num(5)
# 1
# 2 3
# 4 5 6
# 7 8 9 10
# 11 12 13 14 15

 

 

이번 포스팅이 많은 도움이 되었기를 바랍니다. 

행복한 데이터 과학자 되세요!  :-)

728x90
반응형
Posted by Rfriend
,

중심극한정리(Central Limit Theorem, 이하 CLT)는 통계학의 기본 개념으로, 특히 표본 크기가 충분히 큰 경우 모집단의 표본 평균 분포를 설명합니다.

 

1. 중심극한정리(Central Limit Theorem, CLT) 개념

 

(1) 무작위 추출 (Random Sampling): 중심극한정리는 모양이 어떤 분포든지 상관없이 주어진 모집단에서 고정된 크기의 무작위 표본을 추출하고 각 표본의 평균을 계산한다고 가정합니다.

 

(2) 표본 평균 분포 (Distribution of Sample Mean): CLT는 원래 모집단 분포의 모양과 상관없이 표본 평균의 분포가 샘플 크기가 증가함에 따라 정규 분포를 근사화한다고 말합니다. 

 

(3) 크기가 큰 표본 (Large Size of Sample): 정규 분포 근사는 표본 크기가 충분히 큰 경우에 특히 잘 적용되며 일반적으로 n ≥ 30입니다. 그러나 경우에 따라서는 적은 표본 크기에서도 CLT 근사가 가능할 수 있습니다. 특히 기본 모집단 분포가 극도로 편향되지 않은 경우입니다. 

 

 

 

이는 표본 평균의 분포(X bar)가 평균이 모집단 평균(mu)과 같고 표준 편차(sigma/sqrt(n))가 모집단 표준 편차를 표본 크기의 제곱근으로 나눈 값인 정규 분포에 근사적으로 따른다는 것을 의미합니다.

 

중심극한의 정리의 중요성은 그 널리 활용성에 있습니다. 중심극한의 정리를 통계학자와 연구자들은 원래 모집단 분포의 모양을 모르더라도 표본 평균의 분포에 대해 특정 가정을 할 수 있게 됩니다. 이는 통계적 추론(statistical inference), 가설 검정(hypothesis testing) 및 신뢰 구간을 추정(estimate of confidence interval)하는 데 중요하며, 많은 통계적 방법이 정규성 가정(hypothesis of normal distribution)에 의존하기 때문에 실무에서 이러한 통계적 기법의 기초 역할을 합니다.

 

 

 

2. Python을 이용한 중심극한정리 시뮬레이션 

 

다음은 Python을 사용해서 균등분포(uniform distribution)를 따르는 모집단(population)으로 부터 각 표본 크기가 30개인 표본을 1,000번 추출하는 시뮬레이션을 하여 각 표본의 평균을 계산하고, 표본 평균의 분포(distribution of sample mean)를 히스토그램으로 시각화해 본 것입니다. 

 

import numpy as np
import matplotlib.pyplot as plt

# Parameters
population_size = 100000  # Size of the population
sample_size = 30        # Size of each sample
num_samples = 1000      # Number of samples to generate

# Generate a non-normally distributed population (e.g., uniform distribution)
population = np.random.uniform(0, 1, population_size)

# Initialize an array to store the sample means
sample_means = []

# Generate samples and calculate means
for _ in range(num_samples):
    sample = np.random.choice(population, size=sample_size, replace=False)
    sample_mean = np.mean(sample)
    sample_means.append(sample_mean)

# Plot the population and the distribution of sample means
plt.figure(figsize=(12, 6))

# Plot the population distribution
plt.subplot(1, 2, 1)
plt.hist(population, bins=30, color='blue', alpha=0.7)
plt.title('Distribution of Uniform Distribution (Population)')

# Plot the distribution of sample means
plt.subplot(1, 2, 2)
plt.hist(sample_means, bins=30, color='green', alpha=0.7)
plt.title('Distribution of Sample Means')

plt.show()

 

central limit themrem simulation

 

왼쪽 히스토그램이 균등분포를 따르는 모집단의 것이고, 오른쪽 히스토그램은 균등분포를 따르는 모집단으로 부터 무작위 추출한 표본의 평균(sample mean)의 분포를 나타내는 것입니다. 오른쪽의 표본 평균의 분포는 평균 mu=(1+0)/2 = 0.5 를 중심으로 좌우 대칭의 종모양의 정규분포를 따름을 알 수 있습니다. 

 

위의 Python codes 에서 모집단(population) 을 이산형, 연속형 확률분포 별로 바꿔서 시뮬레이션을 해보시면 중심극한정리를 눈으로 확인해볼 수 있습니다. 

(가령, 베타분포의 경우 population = np.random.beta(0.8, 0.8, population_size) 처럼 수정하시면 됩니다)

 

 

 

3. 중심극한정리를 이용한 문제풀이 예시

 

중심극한정리를 이용하여 이항분포의 확률값을 정규분포로 근사해서 구할 수 있습니다. 이항분포는 n 이 비교적 작을 때 (통상 n <= 25) 정확한 확률값을 얻는데 유용하지만 n 이 클 때는 계산이 복잡해집니다. 이 경우 정규분포를 이용하여 이항분포의 확률의 근사값을 구할 수 있습니다. 즉, n이 클수록 또한 p값이 0.5에 가까울수록 이항분포는 정규분포화 유사해집니다. 이산형 확률변수 Y가 이항분포 B(n, p)를 따를 때, 이를 표준화(Z)한 후 표준정규분포 Z~N(0, 1)에 근사시킵니다. 

 

연속형 변수를 사용하여 이산형 변수를 근사할 때에는 연속성 수정계수(continuity correction factor)를 사용하여 오차를 줄입니다. 부등호에 따라 0.5를 가감함으로써 이항분포의 구간을 정규분포의 구간으로 수정합니다. 

 

[예시 문제] 한국인 성인 50%가 최소한 한 개의 신용카드를 가지고 있다고 가정하자.만일 30명의 성인을 표본추출할 때 19명에서 20명 사이의 성인이 최소한 한 개의 신용카드를 소지하고 있을 확률을
(1) 이항분포를 사용하여 구하고, 
(2) 정규근사를 사용하여 구하라. 

 

 

(1) 이항분포를 사용한 풀이

 

이산형 확률변수 Y가 최소한 한 개의 신용카드를 가지고 있을 성인의 수라고 하면, Y~B(30, 0.50)이 됩니다. 이에 대한 확률은 다음과 같이 계산합니다. 

 

이항분포를 사용한 풀이

 

 

 

(2) 정규근사를 사용한 풀이

 

Y~B(30, 0.50)일 때 E(Y)=n*p=30*0.50=15, Var(Y)=n*p*(1-p)=30(0.50)(1-0.50)=7.5 이고, 표준화의 변수를 Z라고 할 때, 이를 정규분포로 근사시킨 후 연속성 수정(+-0.5)을 하여 계산하면 다음과 같습니다. 

 

정규근사를 이용한 풀이

 

이번 포스팅이 많은 도움이 되었기를 바랍니다. 

행복한 데이터 과학자 되세요.  :-)

 

728x90
반응형
Posted by Rfriend
,

이번 포스팅에서는 통계학에서 사용하는 p-값(p-value)이란 무엇이고, 어떻게 해석하는지 소개하겠습니다. 

 

1. 통계학에서 p-value 는 무엇이며, 무엇에 사용하는가? 

2. 독립된 두 표본 간 평균 차이 t-검정에서 p-value 해석 예시

3. Python으로 독립 두 표본 t-검정 (independent two-sample t-test)

4. 빈도론자(Frequentist)와 베이지안(Bayesian) 간 p-value 해석의 차이점은 무엇인가?

 

 

 

1. 통계학에서 p-value 는 무엇이며, 무엇에 사용하는가? 


통계학에서 p-값(확률 값)은 귀무가설(null hypothesis, H0)에 대한 증거를 평가하는 데 도움이 되는 지표입니다. 귀무가설은 차이나 효과가 없다는 것을 나타내는 명제로, 연구자들은 이 귀무가설을 기각할 충분한 증거가 있는지를 판단하기 위해 통계 검정을 사용합니다. 

p-값은 귀무가설이 참일 때 관측 결과나 그보다 더 극단적인 결과가 나올 확률을 나타냅니다. 다시 말해, 이는 귀무가설에 대한 증거의 강도를 측정하는 것입니다.

 


주로 다음과 같은 방식으로 사용합니다. 

(1) 만약 p-값이 작다면(일반적으로 미리 정의된 유의수준, 예를 들어 0.05보다 낮다면), 이는 관측 결과가 무작위로 발생할 가능성이 적다는 것을 나타내며, 이는 귀무가설(null hypothesis, H0)을 기각하고 대립가설(alternative hypothesis, H1)을 채택합니다.

(2) 만약 p-값이 크다면, 이는 관측 결과가 귀무가설과 상당히 일치한다는 것을 나타내며, 귀무가설을 기각할 충분한 증거가 없다는 것을 의미합니다.

 


p-값이 작다고 해서 특정 가설이 참임을 증명하는 것은 아닙니다. 이는 단순히 데이터가 귀무가설과 일치하지 않는다는 것을 나타냅니다. 또한, 유의수준(예: 0.05)의 선택은 어느 정도 임의적이며 연구자의 판단이나 해당 분야의 관례에 따라 달라집니다.

연구자들은 p-값을 신중하게 해석하고 귀무가설 검정에 관한 결정을 내릴 때 다른 관련 정보와 함께 고려해야 합니다. p-값은 효과의 크기나 실제적인 중요성에 대한 정보를 제공하지 않으며, 단지 귀무가설에 대한 증거의 강도(the evidence against a null hypothesis)를 나타냅니다

 



2. 독립된 두 표본 간 평균 차이 t-검정에서 p-value 해석 예시

 

예를 들어 혈압을 낮추는 새로운 약물에 대한 임상시험을 다루는 예를 살펴보겠습니다. 연구자들은 새로운 약물이 플라시보에 비해 혈압을 낮추는 데 효과적인지를 테스트하고자 합니다. 이 맥락에서 p-값의 사용과 해석은 다음과 같을 수 있습니다.

시나리오:

- 귀무가설 (H0): 새로운 약물은 혈압에 아무런 영향을 미치지 않으며, 관측된 차이는 무작위로 발생한 것이다.
- 대립가설 (H1): 새로운 약물은 플라시보에 비해 혈압을 낮추는 데 효과적이다. 즉, 플라시보 그룹보다 신약 그룹의 혈압이 더 낮다.


실험 설계:

- 연구자들은 참가자들을 새로운 약물을 받는 그룹과 플라시보를 받는 그룹으로 무작위로 배정합니다.
- 특정한 치료 기간 이후 각 참가자의 혈압 변화를 측정합니다.


데이터 분석:

- 각 10개의 샘플 데이터를 수집하고 분석한 후, 연구자들은 두 그룹 간의 혈압 변화의 평균을 비교하기 위해 통계적 검정(예: t-검정)을 수행합니다.
- 예를 들어, 검정 결과로 얻은 t-통계량이 3.372, p-값이 0.0017인 경우를 가정해 봅시다.


해석:

- 얻은 p-값(0.0034)이 선택된 유의수준(예: alpah=0.05)보다 작습니다.  
- 빈도주의적 해석: 이는 만약 귀무가설이 사실이라면(즉, 새로운 약물이 효과가 없다면), 실제로 관측된 데이터보다 더 극단적인 데이터를 관측할 확률이 0.17%밖에 되지 않는다는 것을 나타냅니다. 0.0017이 유의수준 0.05 보다 작으므로 연구자들은 귀무가설을 기각하기로 결정할 수 있습니다.
- 결정: 연구자들은 귀무가설을 기각하고 새로운 약물이 플라시보에 비해 혈압을 낮추는 데 효과적임을 시사하는 충분한 증거가 있다고 결론지을 수 있습니다. 

 

아래에는 t-분포표를 수작업으로 해석하는 방법입니다. 

t-분포표의 행은 자유도(degree of freedom) 으로서, 만약 샘플의 관측치 개수가 주어지면 (자유도 =  n-1) 로 계산해줍니다. t-분포표의 열은 유의수준 알파(alpha)이고, 표의 안에 있는 숫자는 가설 검정에 사용하는 t-통계량입니다. (정규분포표에서는 행과 열이 z-통계량이고, 표의 가운데 값이 p-value인데요, t-분포표는 이와 달라서 좀 헷갈리는 면이 있습니다.) 샘플로 부터 자유도와 t-통계량를 계산하면, 아래의 t-분포표를 보고 상단 열에서 p-값을 찾으면 됩니다.  

 

이번 예에서는 가령, 관측치가 각 그룹별로 10개라고 하면, 자유도 = n-1 = 9 가 됩니다. 

그리고 t-통계량을 계산했더니 3.372가 나왔다고 했을 때, 아래 표에서 t-통계량 3.372 는 자유도 9인 행에서 보면 3.250보다는 크고, 3.690보다는 작은 값입니다. 따라서 상단의 알파(alpha) 값은 0.005와 0.0025 사이의 값이라고 추정할 수 있습니다. 그런데 대립가설이 "H1: 새로운 약물은 플라시보에 비해 혈압을 낮추는 데 효과적이다. 즉, 플라시보 그룹보다 신약 그룹의 혈압이 더 낮다." 이므로 단측검정 (alternative = 'greater') 을 사용하므로, p-value=0.005/2=0.0025 보다 작고 ~ p-value=0.0025/2=0.00125 보다는 큰 값으로 볼 수 있습니다. 

 

유의수준 0.05보다는 훨씬 작은 값이므로, 귀무가설을 기각하고 대립가설을 채택합니다. 즉, 신약이 혈압을 낮추는데 효과가 있다고 판단할 수 있습니다. 

 

 

t-분포표 해석하기

 


p-값 자체만으로는 효과의 크기나 임상적 중요성에 대한 정보를 제공하지 않습니다. 연구자들은 통계 검정을 기반으로 의사결정을 내릴 때 효과 크기, 신뢰구간 및 실제적인 중요성도 고려해야 합니다. 또한 베이지안 프레임워크에서는 관측된 데이터를 기반으로 사전 신념을 업데이트하는 것이 포함될 수 있습니다.

 

 

3. Python으로 독립 두 표본 t-검정 (independent two-sample t-test)

 

scipy 모듈의 scipy.stats.stats.ttest_ind() 메소드를 사용해서 독립된 두 표본의 평균에 차이가 있는지를 t-검정해 보겠습니다.

 

- 귀무가설(H0): Group 1과 Group 2의 평균에는 차이가 없다. (mu_g1 = mu_g2)

- 대립가설(H1): Group 1가 Group 2의 평균보다 크다. (mu_g1 > mu_g2)

 

t 통계량이 3.37이고 p-값(p-value)이 0.0034 로서, 유의수준(alpha) 0.05보다 p-값이 더 작으므로 귀무가설을 기각(reject null hypothesis)하고, 대립가설을 채택(accept alternative hypothesis)합니다. 

 

## independent two-sample t-test
import numpy as np
import scipy.stats as stats

# Example data for two independent samples
group1 = [25, 30, 32, 28, 34, 26, 30, 29, 31, 27]
group2 = [21, 24, 28, 25, 30, 22, 26, 23, 27, 24]

print('Mean of Group 1:', np.mean(group1))
print('Mean of Group 2:', np.mean(group2))

# Perform independent two-sample t-test
t_statistic, p_value = stats.ttest_ind(
    group1, group2, 
    equal_var=True,
    alternative='greater', # alternative hypothesis: mu_1 is greater than mu_2
)

# Print the results
print(f'T-statistic: {t_statistic}')
print(f'P-value: {p_value}')

# Check the significance level (e.g., 0.05)
alpha = 0.05
if p_value < alpha:
    print('Reject the null hypothesis. \
There is a significant difference between the groups.')
else:
    print('Fail to reject the null hypothesis. \
There is no significant difference between the groups.')
    
# Mean of Group 1: 29.2
# Mean of Group 2: 25.0
# T-statistic: 3.3723126837047914
# P-value: 0.0016966232763530164
# Reject the null hypothesis. There is a significant difference between the groups.

 




4. 빈도론자(Frequentist)와 베이지안(Bayesian) 간 p-value 해석의 차이점은 무엇인가? 

 

빈도론자(Frequentist)와 베이지안(Bayesian) 간의 통계학적 접근 방식에서 p-값의 해석은 다릅니다. 각 접근 방식이 p-값을 어떻게 해석하는지 간략하게 살펴보겠습니다.

(1) 빈도주의적 해석 (Frequentist Interpretation):

- 빈도주의 통계학에서 p-값은 귀무가설이 참일 때 관측된 데이터나 그보다 더 극단적인 데이터가 나올 확률로 간주됩니다.
- 의사결정 과정은 일반적으로 특정한 유의수준(alpha), 보통 0.05,을 기준으로 귀무가설을 기각하거나 기각하지 않는 것으로 구성됩니다. 
- 만약 p-값이 선택된 유의수준보다 작거나 같으면 귀무가설이 기각됩니다. p-값이 유의수준보다 크면 귀무가설이 기각되지 않습니다.
- 빈도주의 통계학에서는 확률을 가설에 할당하지 않으며 대신 특정 가설 하에서 데이터의 확률에 중점을 둡니다.


(2) 베이지안 해석 (Bayesian Interpretation):

- 베이지안 통계학에서는 관측된 데이터를 기반으로 가설에 대한 사전 신념(prior beliefs)을 업데이트하는 것에 중점을 둡니다.
- 베이지안 분석은 가설에 대한 사전 신념과 관측된 데이터 모두를 고려하여 가설에 대한 사후 확률 분포(posterior probability distribution for the hypothesis)를 제공합니다.
- 베이지안은 의사결정을 위해 일반적으로 p-값 만을 고려하지 않습니다. 대신 전체 사후 분포를 고려하며 이전 정보를 통합합니다. 
- 베이지안 분석은 데이터가 주어졌을 때 가설이 참일 확률을 직접 계산합니다. 이는 빈도주의적 접근과 달리 가설이 주어진 데이터에 대한 확률만을 고려하는 것이 아닙니다.
- 가설 검정을 위해 때로는 베이지안 분석에서는 가설 간의 가능도 비율(ratio of the likehoods under different hypotheses)인 베이즈 팩터(Bayes factor)를 사용하기도 합니다.

요약하면 핵심적인 차이점은 확률 해석에 있습니다. 빈도주의자들은 확률을 사건의 장기적 빈도로 간주하며, 베이지안은 확률을 신념이나 불확실성의 척도로 해석합니다. 빈도주의자들은 p-값을 가설에 대한 의사결정에 사용하며, 베이지안안은 베이지안 추론을 사용하여 직접적으로 신념을 업데이트하고 표현합니다.

 

 

이번 포스팅이 많은 도움이 되었기를 바랍니다. 

 

728x90
반응형
Posted by Rfriend
,

Python의 Dictionary는 {Key: Value}의 쌍(pair)로 이루어진 자료형입니다. 

이번 포스팅에서는 Python Dictionary 를 분할하여 새로운 Dictionary로 만드는 방법을 소개하겠습니다. 

 

(1) Dictionary 의 특정 값을 가진 sub Dictionary 만들기

(2) Dictionary 를 특정 비율로 분할하기

 

 

먼저 예제로 사용할 Dictionary를 만들어보겠습니다. key 는 영어 알파벳이고, value 는 정수 [0, 1, 2] 중에서 무작위로 생성해서 {key: value} 쌍으로 이루어진 Dictionary 입니다. 

 

# Sample Dictionary
import string
import numpy as np
np.random.seed(1004) # for reproducibility

k = list(string.ascii_lowercase)
v = np.random.randint(3, size=len(k))

my_dict = {k: v for k, v in zip(k, v)}

print(my_dict)

# {'a': 2, 'b': 1, 'c': 2, 'd': 0, 'e': 1, 'f': 2, 'g': 1, 
#  'h': 1, 'i': 0, 'j': 0, 'k': 0, 'l': 0, 'm': 0, 'n': 2, 
#  'o': 2, 'p': 0, 'q': 2, 'r': 0, 's': 2, 't': 1, 'u': 0, 
#  'v': 1, 'w': 0, 'x': 2, 'y': 0, 'z': 2}

 

 

 

(1) Dictionary 의 특정 값을 가진 sub Dictionary 만들기

 

먼저 my_dict 내 원소의 value 가 각각 0, 1, 2 인 sub Dictionary  를 만들어보겠습니다. 

my_dict.items() 로 Dictionary 내 원소 값을 불러오고, 조건절이 있는 list comprehension 을 이용하였으며, for loop 순환문을 사용해도 됩니다. 

 

# (1) Split a Dictionary by each value categories of 0, 1, 2
dict_0 = {k: v for k, v in my_dict.items() if v == 0}
dict_1 = {k: v for k, v in my_dict.items() if v == 1}
dict_2 = {k: v for k, v in my_dict.items() if v == 2}

print('Dict 0:', dict_0)
print('Dict 1:', dict_1)
print('Dict 2:', dict_2)

# Dict 0: {'d': 0, 'i': 0, 'j': 0, 'k': 0, 'l': 0, 'm': 0, 'p': 0, 'r': 0, 'u': 0, 'w': 0, 'y': 0}
# Dict 1: {'b': 1, 'e': 1, 'g': 1, 'h': 1, 't': 1, 'v': 1}
# Dict 2: {'a': 2, 'c': 2, 'f': 2, 'n': 2, 'o': 2, 'q': 2, 's': 2, 'x': 2, 'z': 2}

 

 

 

(2) Dictionary 를 특정 비율로 분할하기

 

Split a Dictionary by proportions

 

이제 위에서 생성한 sub Dictionary를 먼저 무작위로 순서를 재정렬한 후에,  [training : validation : test] = [0.6 : 0.2 : 0.2] 의 비율로 분할을 해보겠습니다. 

 

list(dict_k.keys()) 로 각 sub Dictionary 의 key 값을 리스트로 만든 후에, random.shuffle(keys_list) 로 key 값을 무작위로 순서를 재정렬해주었습니다. 

 

그 후에 [train:validation:test] = [0.6:0.2:0.2] 의 비율에 해당하는 각 sub Dictionary의 원소값의 개수를 계산한 후에, 이 원소 개수만큼 keys_list 에서 key 값 리스트를 indexing 해 옵니다.

 

그리고 마지막으로 list comprehension을 이용해서 train, validation, test set 별 key 해당하는 value 를 가져와서 {key: value} 쌍으로 train/validation/test set의 각 Dictionary를 만들어주면 됩니다. 

 

# (2) Split each Dictionary into training set 60%, validation 20%, test set 20% randomly
def split_dict(dict_k, train_r=0.6, val_r=0.2, verbose=False):
    import random
    random.seed(1004) 

    keys_list = list(dict_k.keys())

    # randomize the order of the keys
    random.shuffle(keys_list)

    # numbers per train, validation, and test set
    num_train = int(len(keys_list) * train_r)
    num_val = int(len(keys_list) * val_r)

    # split kyes
    keys_train = keys_list[:num_train] # 60%
    keys_val = keys_list[num_train:(num_train+num_val)] # 20%
    keys_test = keys_list[(num_train+num_val):] # 20% = 1 - train_ratio - val_ratio

    # split a Dictionary
    dict_k_train = {k: dict_k[k] for k in keys_train}
    dict_k_val   = {k: dict_k[k] for k in keys_val}
    dict_k_test  = {k: dict_k[k] for k in keys_test}
    
    if verbose:
        print('Keys List:', keys_list)
        print('---' * 20)
        print('Training set:', dict_k_train)
        print('Validation set:', dict_k_val)
        print('Test set:', dict_k_test)
    
    return dict_k_train, dict_k_val, dict_k_test

 

 

 

실제로 dict_0, dict_1, dict_2 의 각 sub Dictionary에 위에서 정의한 사용자 정의 함수 split_dict() 함수를 적용해보겠습니다. 

 

## (a) split dict_0
dict_0_train, dict_0_val, dict_0_test = split_dict(
    dict_0, 
    train_r=0.6, 
    val_r=0.2, 
    verbose=True
)

# Keys List: ['m', 'r', 'l', 'd', 'j', 'w', 'y', 'k', 'u', 'i', 'p']
# ------------------------------------------------------------
# Training set of Dict 0: {'m': 0, 'r': 0, 'l': 0, 'd': 0, 'j': 0, 'w': 0}
# Validation set of Dict 0: {'y': 0, 'k': 0}
# Test set of Dict 0: {'u': 0, 'i': 0, 'p': 0}


## (b) split dict_1
dict_1_train, dict_1_val, dict_1_test = split_dict(
    dict_1, 
    train_r=0.6, 
    val_r=0.2, 
    verbose=True
)

# Keys List: ['g', 'v', 't', 'e', 'b', 'h']
# ------------------------------------------------------------
# Training set: {'g': 1, 'v': 1, 't': 1}
# Validation set: {'e': 1}
# Test set: {'b': 1, 'h': 1}


## (c) split dict_2
dict_2_train, dict_2_val, dict_2_test = split_dict(
    dict_2, 
    train_r=0.6, 
    val_r=0.2, 
    verbose=True
)

# Keys List: ['f', 'n', 'a', 'x', 'z', 'o', 'q', 'c', 's']
# ------------------------------------------------------------
# Training set of Dict 0: {'m': 0, 'r': 0, 'l': 0, 'd': 0, 'j': 0, 'w': 0}
# Validation set of Dict 0: {'y': 0, 'k': 0}
# Test set of Dict 0: {'u': 0, 'i': 0, 'p': 0}

 

 

 

이번 포스팅이 많은 도움이 되었기를 바랍니다. 

행복한 데이터 과학자 되세요!  :-)

 

728x90
반응형
Posted by Rfriend
,

이번 포스팅에서는

 

(1) pandas.Series.explode() 메소드를 사용해서  Series 안의 리스트를 행으로 변환하기 

(2) pandas.Series.explode() 메소드를 사용해서 DataFrame 안의 리스트를 행으로 변환하기

(3) DataFrame의 float 자리수를 지정해주기

 

방법을 소개하겠습니다. 

 

 

 

 

 

(1) pandas.Series.explode() 메소드를 사용해서  Series 안의 리스트(list)를 행으로 변환하기

 

ignore_index=False 가 디폴트 모드이며, 같은 리스트 내 원소들에 대해서는 같은 인덱스 번호가 부여됩니다. 

 

import pandas as pd

# Series.explode(ignore_index=False)
# Transform each element of a list-like to a row.

s = pd.Series([[4, 9, 6, 1, 8], 'love', [], [3, 0, 1]])

## # by default: ignore_index=False
s.explode(ignore_index=False)

# 0       4
# 0       9
# 0       6
# 0       1
# 0       8
# 1    love
# 2     NaN
# 3       3
# 3       0
# 3       1
# dtype: object

 

 

ignore_index=True 로 설정을 해주면 0, 1, ..., n-1 의 순서대로 인덱스 번호가 부여됩니다. 

 

## If 'ignore_index=True', the resulting index will be labeled 0, 1, …, n - 1.
s.explode(ignore_index=True)

# 0       4
# 1       9
# 2       6
# 3       1
# 4       8
# 5    love
# 6     NaN
# 7       3
# 8       0
# 9       1
# dtype: object

 

 

 

(2) pandas.Series.explode() 메소드를 사용해서 DataFrame 안의 리스트를 행으로 변환하기

 

먼저, 리스트를 원소로 가지는 pandas DataFrame을 예시로 만들어보겠습니다. 바로 이어서 리스트를 풀어서 각 행으로 변환할 것이므로 각 열별 리스트 내 원소의 개수가 서로 같아야 합니다. 

 

## DataFrame with lists
df = pd.DataFrame({
    'grp': [['a', 'a', 'a', 'b', 'b', 'b', 'c', 'c', 'c']], 
    'id': [[1, 2, 3, 4, 5, 6, 7, 8, 9]], 
    'value': [[0.0, 0.421948, 0.9422, 0.582, 0.0, 0.28574, 0.55382, 0.2801, 0.87]]
})

print(df)
#                       grp \
# [a, a, a, b, b, b, c, c, c]  
#
#                       id  \
# [1, 2, 3, 4, 5, 6, 7, 8, 9]   
#                                                               value  
# [0.0, 0.421948, 0.9422, 0.582, 0.0, 0.28574, 0.55382, 0.2801, 0.87]]

 

 

위의 (1)번에서 소개했던 pandas.Series.explode() 메소드를 apply() 함수를 사용해서 위에서 만든 DataFrame df 의 모든 열에 적용해줍니다. 옆으로 길게 리스트 형태로 있던 DataFrame 내 원소가 각 행(row)의 개별 원소로 풀어져서 세로로 긴 DataFrame 형태로 변형되었습니다. 

 

## unpacking the lists in DataFrame
df_unpacked = df.apply(pd.Series.explode)

print(df_unpacked)
#   grp id     value
# 0   a  1       0.0
# 0   a  2  0.421948
# 0   a  3    0.9422
# 0   b  4     0.582
# 0   b  5       0.0
# 0   b  6   0.28574
# 0   c  7   0.55382
# 0   c  8    0.2801
# 0   c  9      0.87

 

 

 

(3) DataFrame의 float 자리수를 지정해주기

 

세번째 칼럼인 'value'의 float 값들의 자리수가 서로 달라서 보기에 좋지 않습니다. 이럴 경우 astype(float).round(2) 메소드를 사용해서 소수점 2째 자리로 반올일해서 자리수를 일치시켜주면 보기에 깔끔하고 좋습니다. 

 

## Output to two decimal places
df_unpacked['value'] = df_unpacked['value'].astype(float).round(2)

print(df_unpacked)
#   grp id  value
# 0   a  1   0.00
# 0   a  2   0.42
# 0   a  3   0.94
# 0   b  4   0.58
# 0   b  5   0.00
# 0   b  6   0.29
# 0   c  7   0.55
# 0   c  8   0.28
# 0   c  9   0.87

 

 

[ Reference ]

* pandas.Series.explode() 메소드

   : https://pandas.pydata.org/docs/reference/api/pandas.Series.explode.html

 

 

이번 포스팅이 많은 도움이 되었기를 바랍니다. 

행복한 데이터 과학자 되세요!  :-)

 

728x90
반응형
Posted by Rfriend
,

이번 포스팅에서는 리스트와 사전 자료형을 이용해서 문자열과 숫자를 서로 매핑하고 변환하는 방법을 소개하겠습니다. 

(예전에 이와 비슷한 포스팅을 한적이 있는데요, 예전 거에서 한 발자국씩만 더 나가봤습니다.)

 

(1) 리스트 내 문자열을 숫자로 변환하기

(2) 리스트 내 숫자를 문자열로 변환하기

(3) 고유한 문자열에 정수를 매핑하기 

(4) 고유한 정수에 문자열을 매핑하기 

 

 

 

(1) 리스트 내 문자열 을 숫자로 변환하기

 

* 방법 1: Python의 List Comprehensionint(str) 메소드를 같이 사용하는 방법입니다. 

 

## Converting string list to integer list

str_list = ['5', '12', '8', '19', '34']

## way 1: list comprehension
int_list = [int(x) for x in str_list]

print(int_list)
# [5, 12, 8, 19, 34]

 

 

* 방법 2: map() 메소드를 사용해서 list(map(int, string_list)) 형태로 사용하는 방법입니다. 

 

## way 2: map(int, str) function
int_list2 = list(map(int, str_list))

print(int_list2)
# [5, 12, 8, 19, 34]

 

 



(2) 리스트 내 문자열을 숫자로 변환하기

 

리스트 안의 문자열을 숫자로 바꾸는 방법은 위의 (1)번에서 소개한 2가지 방법과 동일하며, int() 대신 str()을 사용해주면 됩니다. 

 

## converting integer to string

## way 1: list comprehension
[str(i) for i in int_list]
# ['5', '12', '8', '19', '34']


## way 2: map(str, int_list)
list(map(str, int_list))
# ['5', '12', '8', '19', '34']

 

 

 

(3) 고유한 문자열에 정수를 매핑하기 

 

(3-1) sorted(set(label_list)) : 먼저 문자열 리스트 에서 유일한(unique) 문자열 집합을 추출해서 정렬한 후에 

          --> {k: v+1 for v, k in enumerate(sorted(set(label_list)))} 
                : 유일한 문자열 별로 1부터 순차적으로 정수를 부여한 사전 자료형을 만듭니다 (향후 매핑 참조에 사용됨)

 

## original label list
label_list = ['cat', 'dog', 'cat', 'car', 'tree', 'tree', 'dog']

sorted(set(label_list))
# ['car', 'cat', 'dog', 'tree']


## mapping index dictionary(label key: integer value)
label_int_dict = {
    k: v+1 for v, k in enumerate(
        sorted(set(label_list))
    )
}


print(label_int_dict)
# {'car': 1, 'cat': 2, 'dog': 3, 'tree': 4}

 

 

(3-2) for x in label_list : label_list 에서 순서대로 문자열 원소값을 for loop 순환문을 통해 하나씩 가져와서 

          --> [label_int_dict[x]] : 위의 (3-1)에서 생성한 매핑 사전에서 문자열에 해당하는 정수를 매핑해주고 리스트로 만들어줍니다. 

 

## mapping label to integer index using list comprehension
mapped_int_list = [label_int_dict[x] for x in label_list]

print(mapped_int_list)
# [2, 3, 2, 1, 4, 4, 3]

 

 

 

(4) 고유한 정수에 문자열을 매핑하기 

 

(4-1) for k, v in label_int_dict.items() : 위의 (3-1)에서 생성한 문자열-정수 매핑 사전에서 Key, Value 를 불러와서 

          --> {v: k} : {Value: Key} 로 서로 키와 값의 위치를 바꾸어서 새로 사전 자료형을 만들어줍니다. 

                             (아래 (4-2)에서 매핑 사전으로 사용됨) 

 

## converting integer to label string
int_label_dict = {
    v: k for k, v in label_int_dict.items()
}

print(int_label_dict)
# {1: 'car', 2: 'cat', 3: 'dog', 4: 'tree'}

 

 

(4-2) for x in mapped_int_list : 위의 (3-2)에서 변환했던 mapped_int_list 리스트에서 정수를 하나씩 불러와서 

          --> [int_label_dict[x]] : (4-1)에서 생성한 {정수: 문자열} 매핑 사전을 이용해서 정수에 해당하는 문자열을 매핑하고 리스트로 만들어줍니다. 

 

## mapping integer to label using list comprehension
mapped_label_list = [int_label_dict[x] for x in mapped_int_list]

print(mapped_label_list)
# ['cat', 'dog', 'cat', 'car', 'tree', 'tree', 'dog']

 

 

 

이번 포스팅이 많은 도움이 되었기를 바랍니다. 

행복한 데이터 과학자 되세요!  :-)

 

728x90
반응형
Posted by Rfriend
,

이번 포스팅에서는 Python의 Plotly 모듈을 이용해서 클리브랜드 점 그래프 (Cleveland Dot Plot in Python using Plotly) 그리는 방법을 소개하겠습니다. 

 

Cleveland and McGill (1984) 이  “Graphical Methods for Data Presentation: Full Scale Breaks, Dot Charts, and Multibased Logging.” 이라는 논문에서 막대 그래프 대비 점 그래프가 데이터 해석, 가독성에서 가지는 우수성을 소개하면서 Cleveland Dot Plot 이라고도 많이 불리는 그래프입니다.

 

예제로 사용할 데이터로, "학교(schools)" 범주형 변수의 졸업생 별 남성(men)과 여성(women)의 수입(earning) 데이터로 pandas DataFrame을 만들어보겠습니다. 

 

## making a sample pandas DataFrame
import pandas as pd

df = pd.DataFrame({
    'schools': [
        "Brown", "NYU", "Notre Dame", "Cornell", "Tufts", "Yale",
        "Dartmouth", "Chicago", "Columbia", "Duke", "Georgetown",
        "Princeton", "U.Penn", "Stanford", "MIT", "Harvard"],
    'earnings_men': [
        92, 94, 100, 107, 112, 114, 114, 118, 119, 124, 131, 137, 141, 151, 152, 165], 
    'earnings_women': [
        72, 67, 73, 80, 76, 79, 84, 78, 86, 93, 94, 90, 92, 96, 94, 112]
})



print(df)
#        schools  earnings_men  earnings_women
# 0        Brown            92              72
# 1          NYU            94              67
# 2   Notre Dame           100              73
# 3      Cornell           107              80
# 4        Tufts           112              76
# 5         Yale           114              79
# 6    Dartmouth           114              84
# 7      Chicago           118              78
# 8     Columbia           119              86
# 9         Duke           124              93
# 10  Georgetown           131              94
# 11   Princeton           137              90
# 12      U.Penn           141              92
# 13    Stanford           151              96
# 14         MIT           152              94

# 15     Harvard           165             112

 

 

Plotly 의 graph_objects 메소드를 사용해서 졸업한 학교(schools) 별 남성의 수입(earnings_men)과 여성의 수입(earnings_women) 에 대해서 점으로 마킹을 하고 수입을 텍스트로 표기 (mode="markers + text") 하여 클리브랜드 점 그래프 (Cleveland Dot Plot)을 그려보겠습니다. 

 

import plotly.graph_objects as go

fig = go.Figure()

## Dot Plot for Men
fig.add_trace(go.Scatter(
    x=df['earnings_men'],
    y=df['schools'],
    marker=dict(color="red", size=10),
    mode="markers + text",
    name="Men",
    text=df['earnings_men'],
    textposition="middle right"
))

## Dot Plot for Women
fig.add_trace(go.Scatter(
    x=df['earnings_women'],
    y=df['schools'],
    marker=dict(color="blue", size=10),
    mode="markers + text",
    name="Women",
    text=df['earnings_women'],
    textposition="middle left"
))

## title and axis title
fig.update_layout(
    title="Earnings by School and Gender",
    xaxis_title="Annual Salary (in thousands)",
    yaxis_title="School")


fig.show()

Cleveland Dot Plot in Python using Plotly

 

Plotly 그래프는 interactive mode 로서 마우스 커서를 그래프에 가져다대면 해당 점의 정보가 팝업으로 나타나서 편리하게 볼 수 있습니다. 

 

R의 ggplot2 패키지를 이용한 클리브랜드 점 그래프 (Cleveland Dot Plot in R using ggplot2) 그리는 방법은 https://rfriend.tistory.com/75 를 참고하세요. 

 

이번 포스팅이 많은 도움이 되었기를 바랍니다. 

행복한 데이터 과학자 되세요!  :-)

 

 

728x90
반응형
Posted by Rfriend
,

이번 포스팅에서는 Python 의 Plotly 모듈을 사용해서 

 

(1) 3차원 산점도 그리기 (3D Scatter Plot using Plotly)

(2) 3차원 표면도 그리기 (3D Surface Plot using Plotly) 

 

하는 방법을 소개하겠습니다 

 

 

 

(1) 3차원 산점도 그리기 (3D Scatter Plot using Plotly)

 

3차원 산점도는 x, y, z 의 3개 축을 기준으로 3차원의 공간에 산점도를 그려서 3개 변수들 간의 관계를 분석하기 위해서 사용합니다. 마커의 크기와 색깔을 달리해서 4번째 변수의 특성을 3차원 산점도에 추가해서 그릴 수도 있습니다. 

 

Scatter3D trace 는 go.Scatter3D() 함수에 의해 반환되는 그래프 객체입니다. 3차원 산점도이기 때문에 x, y, z 의 좌표값을 반드시 넣어줘야 하며, 이들 값은 리스트(List) 또는 Array 객체를 사용합니다. 

 

아래는 싸인과 코싸인 값을 이용해서 3차원 산점도를 그려본 예입니다. 

 

import plotly.graph_objs as go
import numpy as np

z = np.linspace(0, 10, 50)
x = np.cos(z)
y = np.sin(z)

trace = go.Scatter3d(
   x = x, 
   y = y, 
   z = z,
   mode = 'markers', 
   marker = dict(
      size = 12,
      color = z, 
      colorscale = 'Bluered_r'
      )
   )

layout = go.Layout(title = '3차원 산점도 (3D Scatter plot)')

fig = go.Figure(data = [trace], layout = layout)

fig.show()

3D Scatter Plot in Python using Plotly

 

 

 

(2) 3차원 표면도 그리기 (3D Surface Plot using Plotly) 

 

3차원 표면도는 위도(x, latitude), 경도(y, longitude), 고도(z, altitude) 의 3차원 데이터를 그래프로 표현한 것입니다. 이때 3차원 데이터 값을 개별 점(indivisual points)으로 표현한 대신에 표면(surface)으로 표현하여서 3차원 데이터 간의 관계를 분석할 때 사용합니다.

 

이때 위도(x, latitude), 경도(y, longitude)는 독립변수(indepedent variable)이 되고, 고도(z, altitude)는 종속변수(dependent variable) 가 됩니다. 

 

아래 예는 Plotly의 graph_objs 메소드 중에서 go.Surface() 메소드를 사용해서 3차원 표면도를 그려면 것입니다. 

 

import numpy as np
import plotly.graph_objs as go

x = np.outer(np.linspace(-2, 2, 30), np.ones(30))
y = x.copy().T # transpose
z = np.cos(x ** 2 + y ** 2)

trace = go.Surface(x = x, y = y, z =z )
data = [trace]

layout = go.Layout(title = '3차원 표면도 (3D Surface Plot)')

fig = go.Figure(data = data, layout=layout)

fig.show()

 

 

Plotly 그래프는 interactive mode 를 지원하기 때문에 마우스 커서를 그래프 위에 가져가면 해당 좌표의 정보가 팝업으로 나타납니다. 그리고 커서를 클릭해서 위-아래-좌-우 방향으로 이동하면 3차원 표면도가 방향이 돌아가기 때문에 입체적으로 3차원 표면을 관찰할 수 있는 장점이 있습니다. 

 

 

[Reference]

* Plotly - 3D Scatter and Surface Plot
 : https://www.tutorialspoint.com/plotly/plotly_3d_scatter_and_surface_plot.htm

 

 

이번 포스팅이 많은 도움이 되었기를 바랍니다 .

행복한 데이터 과학자 되세요!  :-)

 

 

 

728x90
반응형
Posted by Rfriend
,

이번 포스팅에서는 Python 의 Pandas 에서 함수를 적용할 때 사용하는 map(), applymap(), apply() 메소드에 대해서 알아보겠습니다. 

 

(1) map(): Series 에 대해 element-wise 로 함수 적용

(2) applymap(): DataFrame에 대해 element-wise 로 함수 적용

(3) apply(): DataFrame에 대해 행/열 (row/column) 로 함수 적용

 

 

Pandas 함수 적용하기: map, applymap, apply

 

 

(1) map(): Series 에 대해 element-wise 로 함수 적용

 

예제로 사용할 DataFrame을 만들어보겠습니다. 

 

import numpy as np
import pandas as pd

## making a sample pandas DataFrame
np.random.seed(1004)

df = pd.DataFrame(
    np.random.randn(4, 3), 
    columns=['x1', 'x2', 'x3'], 
    index=['A', 'B', 'C', 'D'])

print(df)
#          x1        x2        x3
# A  0.594403  0.402609 -0.805162
# B  0.115126 -0.753065 -0.784118
# C  1.461576  1.576076 -0.171318
# D -0.914482  0.860139  0.358802

 

 

 

map() 메소드는 pandas Series 에 대해 함수를 적용할 때 사용합니다. 아래 예제는 익명 함수 lambda 로 정의한 s_formater 함수를 map() 메소드로 Series에 적용해 본 것입니다. 

 

## pandas Series
df['x1']
# A    0.594403
# B    0.115126
# C    1.461576
# D   -0.914482
# Name: x1, dtype: float64


## map: applying an element-wise function for Series
s_formater = lambda x: '%.2f'% x

df['x1'].map(s_formater)
# A     0.59
# B     0.12
# C     1.46
# D    -0.91
# Name: x1, dtype: object

 

 

 

아래 예제에서는 Series의 인덱스를 키로 해서 매핑(mapping by index)하여 Series의 값을 변환한 것입니다. 

-------------------------------------------------------

s_1 인덱스 --> s_1 값 = s_2 인덱스  -->  s_2 값

-------------------------------------------------------

'a'             -->             0                    -->     'A'

'b'             -->             1                     -->     'B'

'c'             -->             2                     -->     'C'

-------------------------------------------------------

 

 

## 예제 pandas Series 만들기
s_1 = pd.Series({'a': 0, 'b': 1, 'c': 2})
s_2 = pd.Series({0: 'A', 1: 'B', 2: 'C'})

print(s_1)
# a    0
# b    1
# c    2
# dtype: int64

print(s_2)
# 0    A
# 1    B
# 2    C
# dtype: object


##-- 인덱스 키를 기준으로 매핑하기 (mapping by index on Series)
print(s_1.map(s_2))
# a    A
# b    B
# c    C
# dtype: object

 

 

 

(2) applymap(): DataFrame에 대해 element-wise 로 함수 적용

 

다음 예제는 applymap() 메소드를 사용해서 익명함수 lambda 로 정의한 s_formater 함수를 DataFrame 의 각 원소에 대해 적용한 것입니다. (map() 은 Series 대상 vs. applymap()은 DataFrame 대상 element-wise 함수 적용)

 

## applymap: applying an element-wise for DataFrame
s_formater = lambda x: '%.2f'% x

df_2 = df.applymap(s_formater)

print(df_2)
#       x1     x2     x3
# A   0.59   0.40  -0.81
# B   0.12  -0.75  -0.78
# C   1.46   1.58  -0.17
# D  -0.91   0.86   0.36

 

 

 

(3) apply(): DataFrame에 대해 행/열 (row/column) 로 함수 적용

 

아래 예제는 column 기준 (axis=0),  row 기준 (axis=1) 으로 익명함수 lambda로 정의한 (열 또는 행 기준, 최대값 - 최소값) 을 계산하는 함수를 apply() 메소드로 DataFrame에 대해 적용해본 것입니다. 

 

## apply: applying a function on row/column basis of a DataFrame
f = lambda x: x.max() - x.min()

## on column basis
df.apply(f, axis=0)

# x1    2.376058
# x2    2.329141
# x3    1.163964
# dtype: float64



## on row basis
df.apply(f, axis=1)

# A    1.399565
# B    0.899243
# C    1.747393
# D    1.774621
# dtype: float64

 

 

 

아래 예는 apply() 메소드를 써서 DataFrame에 행(row) 기준으로 최대값을 계산하는 익명함수 lambda로 정의한 함수를 적용해서 'x_max'라는 새로운 칼럼을 추가한 것입니다. 

 

## 새로운 칼럼 추가하기
df['x_max'] = df.apply(lambda x: x.max(), axis=1)

print(df)
#          x1        x2        x3     x_max
# A  0.594403  0.402609 -0.805162  0.594403
# B  0.115126 -0.753065 -0.784118  0.115126
# C  1.461576  1.576076 -0.171318  1.576076
# D -0.914482  0.860139  0.358802  0.860139


## equivalent
df['x_max'] = df.max(axis=1)

 

 

* Pandas DataFrame에서 여러개의 칼럼에 대해 그룹을 집계를 할 때 다른 집계 함수를 적용하는 방법은 https://rfriend.tistory.com/393 를 참고하세요. 

 

* Python의 익명 함수 lambda 에 대해서는 https://rfriend.tistory.com/366 를 참고하세요. 

 

 

이번 포스팅이 많은 도움이 되었기를 바랍니다. 

행복한 데이터 과학자 되세요!  :-)

 

728x90
반응형
Posted by Rfriend
,

이번 포스팅에서는 Python의 List Comprehension 에 대해서 알아보겠습니다.

(번역하기가 애매해서 영어 원문 그대로 사용하겠습니다)

 

1. List Comprehension 이란? 

 

Python의 List Comprehension 은 기존에 존재하는 List 에서 새로운 List 를 간결하게 생성하는 방법입니다.

 

List Comprehension Syntax 는 아래와 같습니다. 

new_list = [expression for item in iterable if condition == True]

 

 

 

간단한 예를 들어서 설명해보겠습니다.  아래에 6개의 도시를 원소로 가지는 List 가 있습니다. 첫글자가 "S"로 시작하는 도시명을 원소로 가지는 새로운 List를 만든다고 했을 때, for loop 순환문과 if 조건절을 사용하는 방법이 있습니다. 

 

city_list = ["Seoul", "New York", "London", "Shanghai", "Paris", "Tokyo"]

print(city_list)
# ['Seoul', 'New York', 'London', 'Shanghai', 'Paris', 'Tokyo']


## way 1: for loop and if conditional statement
city_s_1 = []

for city in city_list:
    if "S" in city:
        city_s_1.append(city)
        
        
print(city_s_1)
# ['Seoul', 'Shanghai']

 

 

첫글자가 "S"로 시작하는 도시명을 원소로 가지는 새로운 List를 만든다고 했을 때, List Comprehension 을 이용하면 아래와 같이 아주 간결하게 코드를 짤 수 있습니다. 

 

## way 2: List Comprehension
## [expression for item in iterable if condition == True]
city_s_2 = [city for city in city_list if "S" in city]

print(city_s_2)
# ['Seoul', 'Shanghai']

 

 

 

2. 내장 range() 함수와 조건절을 사용한 List Comprehension

 

Python의 iterable 자료형으로 str, list, tuple, dictionary, set, range 등이 있는데요, 아래 예에서는 그중에서 내장 range() 함수로 0~9까지의 정수를 반복적으로 생성해서, if 조건절을 사용해 짝수로 구성된 새로운 List 를 만들어보겠습니다. 

 

## range() 함수와 List Comprehension 으로 짝수 리스트 만들기
even_list = [i for i in range(10) if i%2 == 0]

print(even_list)
# [0, 2, 4, 6, 8]

 

 

 

3. if else 조건절을 사용해서 List Comprehension 만들기

 

if else 조건절을 List Comprehension 에서 사용할 때는 if else 조건절을 앞에 써주고, for loop 순환문을 뒤에 사용해줍니다. (* 위의 2번과 순서가 뒤바뀜에 주의)

 

## 짝수는 그대로, 홀수이면 99로 치환한 리스트
## if else 조건절이 앞에 있고, for 순환문이 뒤에 있음
if_else_list = [i if i%2 == 0 else 99 for i in range(10)]

print(if_else_list)
# [0, 99, 2, 99, 4, 99, 6, 99, 8, 99]

 

 

만약 for loop 순환문을 앞에 써주고 if else 조건절을 뒤에 써서 List Comprehension 을 시도하면 SyntaxError 가 납니다. 

 

## SyntaxError: invalid syntax
[i for i in range(10) if i%2 == 0 else 99] #SyntaxError

 

 

 

4. 2D List 에 대해 중첩된 순환문(Nested for loops)을 사용해서 List Comprehension 

 

4-1.  2D List 를 1D List 로 차원 줄이기 (flattening)

 

list_2d = [[11, 12], 
           [21, 22], 
           [31, 32], 
           [41, 42]
          ]
          
print(list_2d)
# [[11, 12], [21, 22], [31, 32], [41, 42]]


## flattening
## flattening
list_1d = [i for row in list_2d for i in row]

print(list_1d)
# [11, 12, 21, 22, 31, 32, 41, 42]

 

 

4-2. 2D List 를 전치(Transpose) 하기 

 

## Transpose
list_transpose = [[row[i] for row in list_2d] for i in range(2)]

print(list_transpose)
# [[11, 21, 31, 41], [12, 22, 32, 42]]

 

 

 

5. eval() 함수에 List Comprehension 실행하기

 

Python의 eval() 함수는 동적으로 문자열 표현식을 평가하여 실행합니다. (참고: https://rfriend.tistory.com/798 )

eval() 함수에 List Comprehension 을 문자열 표현식으로 넣어서 실행할 수 있습니다. 

 

## eval() 에 list comprehension 표현식(expression)사용 가능
str_list_comprehension = "[i for i in range(10) if i%2 == 0]"

eval(str_list_comprehension)
# [0, 2, 4, 6, 8]

 

 

하지만, 바로 위의 짝수 리스트를 만드는 List Comprehension 과 동일한 과업을 for loop 순환문과 if 조건절 statement 를 문자열로 만들어서 eval() 함수에 넣어 실행하려고 하면 SyntaxError 가 발생합니다. (eval() 함수는 expression 만 평가하여 실행가능하고, statement 는 평가 불가능함)

 

## eval()에 for loop 순환문과 if 조건절 statement 사용 불가
## SyntaxError: invalid syntax
str_for_if = """
new_list = []

for i in range(10):
    if i%2 == 0:
        new_list.append(i)
"""

eval(str_for_if) # SyntaxError: invalid syntax

 

 

 

6. List Comprehension 으로 새로운 Dict 만들기

 

str 자료형은 iterable 타입으로서, 아래처럼 List Comprehension 으로 각 단위문자 별로 쪼개서 새로운 List 로 만들 수 있습니다.  

 

text = "abcde"

print([s for s in text])
# ['a', 'b', 'c', 'd', 'e']

 

 

아래의 예는 range() 함수와 text 를 iterable 하면서 zip() 으로 정수와 각 단위문자를 짝을 이루어서 for loop 순환문으로 발생시키고, 이를  {Key: Value} 로 해서 새로운 Dict 자료형을 만든 것입니다.  

 

## list comprehension을 이용해서 dictionary 만들기
text = "abcde"

{k: v for k, v in zip(range(len(text)), text)}
# {0: 'a', 1: 'b', 2: 'c', 3: 'd', 4: 'e'}

 

 

이번 포스팅이 많은 도움이 되었기를 바랍니다. 

행복한 데이터 과학자 되세요!  :-)

 

728x90
반응형
Posted by Rfriend
,