Tools (127)

반응형

 

R - 롱테일 분포의 히스토그램 그리기

 

실무를 하다보면 롱테일 분포를 많이 접하게 됩니다. 예를 들어서, 어떠한 이커머스 서비스에서 "구매 금액" 이라는 변수를 살펴보면, 대부분의 유저는 구매금액이 0~1만원 사이에 들어있지만, 일부 유저는 구매금액이 몇 백만원 심지어는 몇 억원에 이르는 경우를 심심찮게 볼 수 있습니다. 극심한 right-skewed 분포 (또는 롱테일 분포)의 예라고 볼 수 있습니다. 

 

이러한 롱테일 분포에 일반적인 히스토그램을 적용하게 되면 꼬리가 너무 길어져 가시성이 좋지 않습니다. 이런 경우에 특정 cutff 지점을 정해 따로 범주를 만들곤 합니다. 예를 들어, 구매금액이 백만원 이상인 유저는 '100만원 이상' 이라는 bucket 을 따로 만드는 것이죠. 꼬리 부분이 너무 길기 때문에 이 부분을 따로 모으는 것입니다. 

 

R 코드로는 다음과 같이 작성해볼 수 있습니다. 포인트는 raw 데이터에 적용하는 geom_hist 를 사용하는 것이 아니라, 집계 데이터를 먼저 만든 후, geom_bar 를 통해 히스토그램을 그리는 것입니다. 그리고, 집계 데이터를 만들기 위해 cut 함수를 사용합니다. 

 

R 코드

  • anal_table 데이터 프레임의 value 컬럼이 histogram 을 그리고자하는 변수입니다.
top_1_percent <- quantile(anal_table$value, 0.99, na.rm=T) # 상위 1% 경계값 찾기

# bucket size 동적으로 설정
bucket_size <- 10^ceiling(log10(top_1_percent)) # 초기 bucket size

# while loop를 통해 bucket size 조정
while(TRUE) {
  breaks <- seq(0, top_1_percent, by = bucket_size) # 상위 1% 까지의 bucket  
  if(length(breaks) > 100) break # bucket 개수가 100개 이상이면 loop 탈출
  bucket_size <- bucket_size / 10 # bucket size 재조정
}

labels <- breaks
cutoff <- max(labels)+bucket_size
# 기본적으로 break 에서 좌측을 포함하지 않고 우측을 포함함(include lowest 를 통해 가장 좌측은 포함)
# right=FALSE 를 통해 우측을 포함하지 않게 지정
anal_table$bucket <- cut(anal_table$value, breaks = seq(0, cutoff, by = bucket_size), 
                         include.lowest = TRUE, 
                         right=FALSE,
                         labels = labels)

# bucket 이 없는 경우는, cutoff 이상인 경우로, 따로 만든 bucket 에 속하도록 바꾸어줌 
anal_table <- anal_table %>% mutate(bucket = if_else(is.na(bucket), as.character(ceiling(cutoff)), bucket))
anal_table$bucket <- factor(anal_table$bucket, levels = c(labels, ceiling(cutoff)))

summary_data <- anal_table %>% group_by(bucket) %>% count()
summary_data

summary_data <- summary_data %>% mutate(var_name = var_name)

val_quantile <- quantile((anal_table %>% select(value) %>% pull), probs=seq(0.1, 1, 0.1))

quantile_keys <- names(val_quantile)
quantile_values <- unname(val_quantile)

df_quantile <- data.frame(t(quantile_values))
colnames(df_quantile) <- quantile_keys

df_avg <- anal_table %>% summarize(avg = mean(value))
df_quantile <- cbind(df_quantile, df_avg)
df_quantile <- df_quantile %>% mutate(var_name = var_name)

total_ticks <- 10  

breaks <- pretty_breaks(n = total_ticks)(range(as.numeric(as.character(summary_data$bucket))))
ggplot(summary_data, aes(x = as.numeric(as.character(bucket)), y = n)) +     
  scale_y_continuous(labels = scales::label_comma()) +     
  geom_bar(stat = "identity", fill = "black") +    
  labs(x = "X", y = "Y") +    
  scale_x_continuous(breaks = breaks,  # breaks는 pretty_breaks를 사용해 계산된 값
                     labels = breaks) +   # labels도 breaks를 사용
  theme_bw(base_size = 10, base_family = "Kakao Regular") +    
  ggtitle("Histogram from Binned Data") +      
  theme(plot.margin = margin(0.5, 0.5, 0.5, 0.5, "cm")) +  
  geom_vline(aes(xintercept = df_quantile$avg), colour = "red") +  
  annotate("text", x = df_quantile$avg, y = max(summary_data$n),  
           label = paste("평균 =", round(df_quantile$avg, 2)),  
           vjust = 2, color = "black", size=3)

 

결과 히스토그램

    • 위 코드를 통해 아래와 같이 지정된 bucket size 를 가지며, 상위 1% 이상은 하나의 bucket 으로 묶은 깔끔한 히스토그램을 그릴 수 있습니다.

 

위 코드에는 몇 가지 포인트가 있습니다. bucket size(bin)과 xtick 의 개수를 동적으로 결정한 부분인데요. 이 부분 코드를 좀 더 살펴보겠습니다. 

 

bucket size 를 동적으로 결정하기

  • bucket 의 개수가 최소 100개가 되도록 하며, bucket size 가 1, 10, 100, 1000 처럼 10의 지수형태로 만드는 방법은 아래와 같습니다. 
  • 또한 cut 함수의 labels 를 통해 label 을 이쁘게 만들어줍니다. 예를 들어 label 이 100이라고 하면, (100~199 사이의 bucket 을 의미하는 등)
# while loop를 통해 bucket size 조정
while(TRUE) {
  breaks <- seq(0, top_1_percent, by = bucket_size) # 상위 1% 까지의 bucket  
  if(length(breaks) > 100) break # bucket 개수가 100개 이상이면 loop 탈출
  bucket_size <- bucket_size / 10 # bucket size 재조정
}

labels <- breaks
cutoff <- max(labels)+bucket_size
# 기본적으로 break 에서 좌측을 포함하지 않고 우측을 포함함(include lowest 를 통해 가장 좌측은 포함)
# right=FALSE 를 통해 우측을 포함하지 않게 지정
anal_table$bucket <- cut(anal_table$value, breaks = seq(0, cutoff, by = bucket_size), 
                         include.lowest = TRUE, 
                         right=FALSE,
                         labels = labels)

 

동적 xtick 의 결정

  • 아래 코드는 총 xtick 의 개수를 10개로 고정시키고, 변수에 따라 동적으로 xtick 간격을 조정하는 코드입니다. scalse 라이브러리의 pretty_breaks 라는 함수를 사용합니다. 
library(scales)
total_ticks <- 10  
breaks <- pretty_breaks(n = total_ticks)(range(as.numeric(as.character(summary_data$bucket))))
반응형
반응형

 

rstudio server 에서 github copilot 사용하기

 

rstudio server 환경에서 github copilot 을 사용하려고 보니 아래처럼

Github Copilot integration has been disabled by the administrator 라는 문구가 떴다. 

알아보니, Rstudio Server나 Posit Workbench에서는 관리자 설정 이후 사용이 가능하다고 한다. 

 

관리자 설정 하는 방법은 아래와 같다. rsession.conf 파일을 열고 copilot-enabled=1 문구를 추가해주면 된다!

cd /etc/rstudio/
sudo vim rsession.conf

 

이렇게 Enable github copilot 옵션이 잘 나온다. 

 

반응형
반응형

 

폰트 다운로드 후 위치 변경

sudo mv [폰트 파일 이름].ttf /usr/share/fonts/truetype/

 

extrafont 를 이용해 R 환경에 폰트 설치

library(extrafont)
font_import(prompt=FALSE)  # 폰트 설치 디렉토리를 검색하여 사용 가능한 폰트를 가져옵니다.
fonts()  # 사용 가능한 폰트 목록을 출력합니다.

반응형
반응형

 

어떤 컬럼의 값이 아래와 같은 문자열로 저장되어있을 때

["2021_12","2022_3","2022_1","2022_12","2023_4"....] 

 

해당 문자열 컬럼을 벡터컬럼으로 바꾸고 해당값을 unnest 하는 예시 

하나의 컬럼 값이 벡터형테인 경우 nested 라고 하고, 이를 row 로 변경하는 것을 unnest 라고 한다. 

 

# 문자열 parsing하여 year와 month로 분리하고 각 row로 만들기

df$dates <- lapply(df$month_ids, function(x) {
  unlist(fromJSON(x, simplifyVector = TRUE))
})
df<- df%>% 
  mutate(month_id = map(dates, str_split, pattern = ",")) %>%
  unnest(month_id)



반응형

'Tools > R' 카테고리의 다른 글

rstudio server 에서 github copilot 사용하기  (0) 2024.04.26
R 에서 폰트 사용하는 방법 (linux)  (0) 2024.04.04
R - dictionary 만들기  (0) 2023.03.15
R - 변수 bucketing (카테고리화)  (0) 2023.03.10
R - lag 변수 만들기  (0) 2023.03.10

Tools/R

R - dictionary 만들기

2023. 3. 15. 18:59
반응형

List 를 이용한 방법

# dictionary 생성
dict <- list(name = "John", age = 30, city = "New York")

# dictionary 사용
dict$name
# [1] "John"

dict$age
# [1] 30

dict$city
# [1] "New York"

 

vector 를 활용한 방법

ㄴ setNames 함수를 활용

# dictionary 생성
dict <- setNames(c("John", 30, "New York"), c("name", "age", "city"))

# dictionary 사용
dict$name
# [1] "John"

dict$age
# [1] 30

dict$city
# [1] "New York"

 

hash 함수를 활용한 방법

library(hash)
h <- hash() 
h[['a']] <- 'a'
h[['b']] <- 'b'
h[['c']] <- 'c'
h[['d']] <- 'd'

h[['a']]

 

반응형
반응형

R 에서 특정 변수를 카테고리화 하고 싶을 때가 많다. 

 

다양한 방법이 있지만, 

아래 cut 함수를 사용하는 코드로 0~5, 6~10, 11~15, ... >100 으로 카테고리화가 가능하다. 

cat <- seq(0,100,5)
df$cat <- cut(df$x, breaks = c(cat, Inf), labels = cat)
df$cat <- factor(df$cat, levels=cat)

-> breaks 의 element 보다 labels 의 elements 의 갯수가 1개 적다. 

 

좀 더 일반적으로는 다음과 같다.

# 예시 데이터 생성
set.seed(123)
data <- data.frame(id = 1:10, value = rnorm(10, mean = 50, sd = 10))

# 카테고리화
data$cat <- cut(data$value, breaks = c(0, 25, 50, 75, 100), labels = c("low", "medium-low", "medium-high", "high"))

 

반응형

'Tools > R' 카테고리의 다른 글

R - 리스트 문자열을 벡터로 바꾸고 unnest 하기  (0) 2024.03.06
R - dictionary 만들기  (0) 2023.03.15
R - lag 변수 만들기  (0) 2023.03.10
R - 반복문 대신 사용하는 lapply 패턴  (0) 2023.03.10
R - na to zero  (0) 2023.03.09

Tools/R

R - lag 변수 만들기

2023. 3. 10. 04:03
반응형

Hmisc 의 Lag 변수를 통해 timeseries 데이터의 lag 변수를 만들 수 있다. 

만약, 그룹별 Lag 변수를 만들고 싶으면 dplyr group_by 를 통해 만들 수 있다. 

library(Hmisc)
data <- data %>% group_by(gender, age) %>% mutate(lag = Lag(variable, 1))
반응형

'Tools > R' 카테고리의 다른 글

R - dictionary 만들기  (0) 2023.03.15
R - 변수 bucketing (카테고리화)  (0) 2023.03.10
R - 반복문 대신 사용하는 lapply 패턴  (0) 2023.03.10
R - na to zero  (0) 2023.03.09
R - 컬럼별 동일한 함수 적용을 위한 lapply 테크닉  (0) 2022.09.05
반응형

반복문을 돌면서 여러개의 dataframe 을 만들고, 

이것들을 합쳐서 최종적인 결과 dataframe 을 만드는 경우 아래와 같이 함

 

brand_names <- c("BBQ", "BHC")
tmp_dfs <- lapply(brand_names, function(x){
  p <- paste0(x, "_payment")
  b <- paste0(x, "_buzz")
  tmp_df[1, 'brand'] <- x
  tmp_df[1, 'cor'] <- cor.test(merged[,p], merged[,b])$estimate
  tmp_df
})

df_result <- bind_rows(tmp_dfs)
df_result

출력
> df_result
        cor brand
1 0.6971354   BBQ
2 0.4675438   BHC

반응형

'Tools > R' 카테고리의 다른 글

R - 변수 bucketing (카테고리화)  (0) 2023.03.10
R - lag 변수 만들기  (0) 2023.03.10
R - na to zero  (0) 2023.03.09
R - 컬럼별 동일한 함수 적용을 위한 lapply 테크닉  (0) 2022.09.05
R - aggregate / separate_rows  (0) 2022.06.21

Tools/R

R - na to zero

2023. 3. 9. 22:39
반응형

 

모든 na값을 0로 바꾸기

df[is.na(df)] <- 0

 

특정 컬럼의 na 값을 0으로 바꾸기

df[is.na(df$col_name), 'col_name'] <- 0

 

여러 컬럼의 na 값을 0으로 바꾸기

impute_var <- c('a','b','c')
df[impute_var][is.na(df[impute_var])] <- 0

 

반응형
반응형

 

Pyspark export to delimited file

def myConcat(*cols):
    concat_columns = []
    for c in cols[:-1]:
        concat_columns.append(F.coalesce(c, F.lit("*")))
        concat_columns.append(F.lit("\t"))  
    concat_columns.append(F.coalesce(cols[-1], F.lit("*")))
    return F.concat(*concat_columns)

# combined column 에 모든 변수를 \t 로 concat 한 값 저장 
data_text = data.withColumn("combined", myConcat(*data.columns)).select("combined")
data_text.coalesce(1).write.format("text").option("header", "false").mode("overwrite").save(path)

출처 : https://stackoverflow.com/questions/17837871/how-to-copy-file-from-hdfs-to-the-local-file-system

반응형
반응형