Friday, July 20, 2018

Definition of default


1. Definition of default

452. A default is considered to have occurred with regard to a particular obligor when either or both of the two following events have taken place.
  • The bank considers that the obligor is unlikely to pay its credit obligations to the banking group in full, without recourse by the bank to actions such as realizing security (if held).
  • The obligor is past due more than 90 days on any material credit obligation to the banking group. Overdrafts will be considered as being past due once the customer has breached an advised limit or been advised of a limit smaller than current outstandings.
BCBS128

2. Phương pháp phân loại nợ
Theo khoản 3, Điều 1 Quyết định 18/2007/QĐ-NHNN sửa đổi, bổ sung Điều 6 Quyết định 493/2005/QĐ-NHNN về việc phân chia các nhóm nợ, cụ thể là 5 nhóm:
“a) Nhóm 1 (Nợ đủ tiêu chuẩn) bao gồm:
– Các khoản nợ trong hạn và tổ chức tín dụng đánh giá là có khả năng thu hồi đầy đủ cả gốc và lãi đúng hạn;
– Các khoản nợ quá hạn dưới 10 ngày và tổ chức tín dụng đánh giá là có khả năng thu hồi đầy đủ gốc và lãi bị quá hạn và thu hồi đầy đủ gốc và lãi đúng thời hạn còn lại;
– Các khoản nợ được phân loại vào nhóm 1 theo quy định tại Khoản 2 Điều này.

b) Nhóm 2 (Nợ cần chú ý) bao gồm:
– Các khoản nợ quá hạn từ 10 ngày đến 90 ngày;
– Các khoản nợ điều chỉnh kỳ hạn trả nợ lần đầu (đối với khách hàng là doanh nghiệp, tổ chức thì tổ chức tín dụng phải có hồ sơ đánh giá khách hàng về khả năng trả nợ đầy đủ nợ gốc và lãi đúng kỳ hạn được điều chỉnh lần đầu);
– Các khoản nợ được phân loại vào nhóm 2 theo quy định tại Khoản 3 Điều này.

c) Nhóm 3 (Nợ dưới tiêu chuẩn) bao gồm:
– Các khoản nợ quá hạn từ 91 ngày đến 180 ngày;
– Các khoản nợ cơ cấu lại thời hạn trả nợ lần đầu, trừ các khoản nợ điều chỉnh kỳ hạn trả nợ lần đầu phân loại vào nhóm 2 theo quy định tại Điểm b Khoản này;
– Các khoản nợ được miễn hoặc giảm lãi do khách hàng không đủ khả năng trả lãi đầy đủ theo hợp đồng tín dụng;
– Các khoản nợ được phân loại vào nhóm 3 theo quy định tại Khoản 3 Điều này.

d) Nhóm 4 (Nợ nghi ngờ) bao gồm:
– Các khoản nợ quá hạn từ 181 ngày đến 360 ngày;
– Các khoản nợ cơ cấu lại thời hạn trả nợ lần đầu quá hạn dưới 90 ngày theo thời hạn trả nợ được cơ cấu lại lần đầu;
– Các khoản nợ cơ cấu lại thời hạn trả nợ lần thứ hai;
– Các khoản nợ được phân loại vào nhóm 4 theo quy định tại Khoản 3 Điều này.

đ) Nhóm 5 (Nợ có khả năng mất vốn) bao gồm:

– Các khoản nợ quá hạn trên 360 ngày;
– Các khoản nợ cơ cấu lại thời hạn trả nợ lần đầu quá hạn từ 90 ngày trở lên theo thời hạn trả nợ được cơ cấu lại lần đầu;
– Các khoản nợ cơ cấu lại thời hạn trả nợ lần thứ hai quá hạn theo thời hạn trả nợ được cơ cấu lại lần thứ hai;
– Các khoản nợ cơ cấu lại thời hạn trả nợ lần thứ ba trở lên, kể cả chưa bị quá hạn hoặc đã quá hạn;
– Các khoản nợ khoanh, nợ chờ xử lý;
– Các khoản nợ được phân loại vào nhóm 5 theo quy định tại Khoản 3 Điều này”.

Nợ xấu là nợ thuộc các nhóm 3, 4 và 5.



Thursday, July 12, 2018

Rcode pdf to text

# Text Mining
eng <- read.table("http://www-01.sil.org/linguistics/wordlists/english/wordlist/wordsEn.txt", stringsAsFactors = FALSE)
library(tidyverse)
library(stringr)
#--------------------------------------------------------------------------------------------------------
# 1. Làm việc với chữ cái trong tiếng anh
#--------------------------------------------------------------------------------------------------------
eng <- eng %>% mutate(n_w = str_count(V1))
theme_set(theme_minimal())

# 1.1. Phân bố số lượng chữ cái trong Tiếng Anh:
eng %>%
  group_by(n_w) %>%
  count() %>%
  ggplot(aes(n_w, n)) + geom_col() +
  labs(x = NULL, y = NULL)

# 1.2. Các nguyên âm:
vowels <- c("a", "e", "i", "o", "u")
num_vowels <- vector(mode = "integer", length = 5)
for (j in seq_along(vowels)) {
  num_aux = str_count(eng$V1, vowels[j])
  num_vowels[j] = sum(num_aux)
}

df1 <- data.frame(N = num_vowels, nguyen_am = vowels)

# 1.3. Tần suất xuất hiện các nguyên âm:
library(hrbrthemes)
df1 %>%
  ggplot(aes(reorder(nguyen_am, N), N)) + 
  geom_col() + labs(x = NULL, y = NULL) + coord_flip() +
  scale_y_continuous(breaks = seq(0, 110000, by = 10000)) +
  theme_ipsum(grid = "X")
# 1.4. Tần suất xuất hiện của các chữ cái trong tiếng  Anh:
u <- strsplit(eng$V1, "")
k <- unlist(u)

let <- eng$V1 %>% strsplit("") %>% unlist()
let <- data.frame(l = let)

let %>% group_by(l) %>% count() %>%
  mutate(per = 100*n / nrow(let)) %>%
  mutate_if(is.numeric, function(x) round(x, 2)) %>%
  ggplot(aes(reorder(l, per), per)) + geom_col() +
  coord_flip() +
  labs(x = NULL, y = NULL) +
  theme_ipsum(grid = "X") +
  scale_y_continuous(breaks = seq(1, 12, by = 1))

# Load các gói:
pakg <- c('tm',
          'SnowballC',
          'wordcloud',
          'RColorBrewer')

lapply(pakg, require, character.only = TRUE)
#--------------------------------------------------------------------------------------------------------
# 2. Làm việc với các files pdf
#--------------------------------------------------------------------------------------------------------
# http://data.library.virginia.edu/reading-pdf-files-into-r-for-text-mining/
# 2.1. Đọc các file pdf
setwd("D:/pdftotext/")
files <- list.files(pattern = "pdf$") # lập danh sách file pdf để đọc
Rpdf <- readPDF(control = list(text = "-layout"))
corp2 <- Corpus(URISource(files),
                   readerControl = list(reader = Rpdf))
# -----------------------------------------------------------------
# So sánh với cách đọc của gói pdftools
library(pdftools)
mk <- lapply(files,pdf_text) # Dùng gói pdftools
corp <- Corpus(VectorSource(mk))

print(corp)
print(corp2)

# -----------------------------------------------------------------

# 2.2. Loại những từ không liên quan
# Bỏ các từ như cengage, learning vì cengage learning là tên của nhà in. Sẽ không hợp lí nếu tính chúng vào  phân  tích:
corp <- corp %>% tm_map(removeWords, c("cengage", "learning"))
# Xóa tất cả các loại dấu câu như chấm, phẩy
# Sử dụng hàm này tốt hơn so với hàm mặc định
replacePunctuation <- function(x) {
  gsub("[[:punct:]]+", " ", x) }
corp <- corp %>% tm_map(replacePunctuation)
# corp <- corp %>% tm_map(removePunctuation) # Do hàm này sẽ không để khoảng trống khi remove .
# Ví dụ:
removePunctuation("hello...world")
#
# Bỏ các Stop Word trong tiếng Anh:
corp <- corp %>% tm_map(removeWords, stopwords("english")) # tùy thuộc stopwords trong từng hàm, số lượng từ bị xóa sẽ khác nhau
# Chuyển hóa tất về chữ in thường:
corp <- corp %>% tm_map(content_transformer(tolower))
# Chuyển động từ về nguyên dạng, không chia, không nên dùng, vì nó bỏ hết cả chữ e cuối từ
corp <- corp %>% tm_map(PlainTextDocument)
corp <- corp %>% tm_map(stemDocument, "english")
# Bỏ các con số:
corp <- corp %>% tm_map(removeNumbers)
# Xóa khoảng trắng
corp <- corp %>% tm_map(stripWhitespace)

# 2.3. Chuyển hóa về Document Matrix: -------------------------------------------------------------
# Nếu có lỗi dùng hàm dưới
# corp <- tm_map(corp, content_transformer(function(x) iconv(enc2utf8(x), sub = "byte")))
tdm <- TermDocumentMatrix(corp)

# Kiểm tra tdm
inspect(tdm[1:10,])
m <- as.matrix(tdm)
v <- sort(rowSums(m), decreasing = TRUE)
d <- data.frame(word = names(v), freq = v)

str(d)

# Chuyển hóa factor về character: 
d$word <- as.character(d$word)
# Danh sách của 500 từ xuất hiện  nhiều nhất trong
# cuốn sách của Gujarati cùng tần suất tương ứng: 
knitr::kable(d %>% slice(1:500))

# 500 từ này chiếm 75.9% tất cả các từ vựng mà tác giả dùng để viết sách:
sum(d$freq[1:500]) / sum(d$freq)
# Trong khi đó 500 từ kế tiếp chỉ chiếm 12.5%
sum(d$freq[1:1000]) / sum(d$freq)

#-----------------------------------------------------
# Dưới đây chúng ta lọc ra hai bộ dữ liệu riêng biệt.
# Bộ  thứ nhất là những từ thuộc bộ từ điển tiếng Anh.
# Bộ  còn  lại không  thuộc.
#-----------------------------------------------------

# Bộ thứ nhất chủ yếu là các từ phổ thông: 

gu_eng <- d %>% filter(word  %in% eng$V1)

# Bộ thứ hai hầu  hết là từ chuyên ngành Thống kê - Kinh tế lượng:
gu_non_eng <- dplyr::setdiff(d, gu_eng)
# Tổng số từ vựng sử dụng để viết sách là 9078:
nrow(d)

nrow(gu_eng)

nrow(gu_non_eng)

nrow(gu_non_eng) / nrow(d)

knitr::kable(gu_non_eng %>% filter(freq >= 100))

knitr::kable(head(gu_non_eng, 200))

#--------------------------------------------------------------------------------------------------------
# 3. Vẽ đám mây từ
#--------------------------------------------------------------------------------------------------------

#  Cho 100 từ xuất hiện  nhiều  nhất ở bộ 1:
par(bg = "black")
set.seed(15888)
wordcloud(words = gu_eng$word,
          freq = gu_eng$freq,
          # Chỉ hiện thị từ nào xuất hiện  ít nhất 100  lần:
          min.freq = 100,
          # Số từ hiển thị trên wordcloud tối đa là 200:
          max.words = 200,
          # Ngẫu  nhiên thứ tự:
          random.order = FALSE,
          # 35% số từ được hiển thị theo chiều thẳng đứng
          rot.per = 0.35,
          # Chọn kích cỡ chữ:
          font = 2,
          # Tô màu cho chữ:
          colors = brewer.pal(8, "Dark2"))

# Cho 100 từ xuất hiện ở bộ 2:
set.seed(1409)
wordcloud(words = gu_non_eng$word,
          freq = gu_non_eng$freq,
          # Chỉ hiện thị từ nào xuất hiện  ít nhất 10  lần
          min.freq = 10,
          # Số từ hiển thị trên wordcloud tối đa là 200:
          max.words = 200,
          # Ngẫu  nhiên thứ tự:
          random.order = FALSE,
          # 35% số từ được hiển thị theo chiều thẳng đứng
          rot.per = 0.35,
          # Chọn kích cỡ chữ:
          font = 2,
          # Tô màu cho chữ:
          colors = brewer.pal(8, "Dark2"))

Tuesday, July 10, 2018

Rcode advanced dplyr


rm(list = ls())

data("starwars")

#
names(starwars)
head(starwars)

# Đối tên biến
starwars %>% rename(sex = gender)


x1 <- starwars %>% slice(1:5) %>% select(hair_color, gender)
x1
x2 <- starwars %>% slice(6:10) %>% select(hair_color, gender)
x2

# Lấy tập giao (có trong cả 2 tập hợp)
x1 %>% intersect(x2)

# Lấy tập khác (chỉ có ở x1 mà ko có ở x2)
x1 %>% setdiff(x2)
# Chỉ có ở x2 mà ko có ở x1
x2 %>% setdiff(x1)

# lấy tập hợp (có ở x1 hoặc x2)
x1 %>% union(x2)

starwars %>% slice(1:5) %>% select(hair_color, gender) %>%
  union(starwars %>% slice(6:10) %>% select(hair_color, gender)) # kết quả tương tự

# Tạo biến số thứ tự dòng
x1 %>% mutate(id=row_number())
x1 %>% mutate(id=row_number(gender))

# Lấy hạng bằng giá trị min của nhóm bằng nhau
x1 <- starwars %>% slice(10:20) %>% select(hair_color, gender, height)
x1 %>% mutate(rk = min_rank(gender))
x1 %>% mutate(rk = min_rank(hair_color))
x1 %>% mutate(rk = min_rank(height))

# Lấy hạng bằng dense_rank
x1 %>% mutate(rk = dense_rank(gender))
x1 %>% mutate(rk = dense_rank(hair_color))

# percent_rank,
x1 %>% mutate(prk = percent_rank(height))
x1 %>% mutate(prk = percent_rank(height)) %>% mutate(sprk = sum(prk))

#
x1 %>% mutate(prk = cume_dist(height))
x1 %>% mutate(prk = cume_dist(height)) %>% mutate(sprk = sum(prk))

#
select_if(starwars, funs(is.numeric))
select_at(starwars, vars("name", "height"))

#
starwars %>% rename_all(funs(paste0("sw_", .)))
starwars %>% rename_if(funs(is.numeric), funs(str_to_upper)) # những biến là numeric thì sẽ in hoa
starwars %>% rename_at( vars("name", "height"), funs(str_to_upper))

#
starwars %>% filter_at(vars(contains("color")), all_vars(. == "brown"))
starwars %>% filter_at(vars(contains("color")), any_vars(. == "brown"))
starwars %>% filter_if(is.numeric, all_vars(. > 100))

#
starwars %>% mutate_all(as.character)
starwars %>% mutate_if(funs(is.character), funs(as.factor))
starwars %>% mutate_at(vars("height"), funs(. / 10))

#
starwars %>%
  select(1:3) %>%
  mutate(sum(height, na.rm=T))

starwars %>%
  select(1:3) %>%
  mutate(sum(height, mass, na.rm=T)) # công hết cả 2 dãy số vào với nhau

starwars %>%
  select(1:3) %>%
  group_by_all() %>% # group hết tất cả các biến
  mutate(sum(height, mass, na.rm=T))

starwars %>%
  select(1:3) %>%
  group_by_if(is.character) %>% # group nếu là biến character
  count()


group_by_at(starwars, vars("eye_color", "hair_color")) %>%  # không cần phải select
  count()

starwars %>%
  select_if(funs(is.numeric)) %>%  # chọn theo điều kiện
  summarise_all(funs(mean), na.rm = T)

starwars %>% summarise_if(funs(is.numeric), funs(min, median, mean, sd, max), na.rm = T)

starwars %>%
  summarise_if(funs(is.numeric), funs(min, median, mean, sd, max), na.rm = T) %>%
  gather() %>% # chuyển sang dạng long
  arrange(key)

starwars %>%
  summarise_if(funs(is.numeric), funs(min, median, mean, sd, max), na.rm = T) %>%
  gather() %>% # chuyển sang dạng long
  arrange(key)

starwars %>% summarise_at(vars("height", "mass"), funs(sum, mean), na.rm = T)

starwars %>%
  summarise_all(funs(sum(is.na(.)))) %>%
  select_if(any_vars(. > 0))

# Tham khảo: http://rpubs.com/hodgeasaurus/397278

Rcode trích diện tích từ đoạn text


load_pkg <- function(pkg){
  library(pkg, character.only = T)
  return('NNB')
}

pkgs <- c('tidyverse','magrittr', 'stringr', 'stringi', 'readxl', 'writexl', 'tidytext')
sapply(pkgs, load_pkg)

my_path <- 'D:/dt_crawled/'

d3 <- read_excel(paste0(my_path, 'Muaban_All_20June2018.xlsx'), sheet = 3)

head(d3$mb_long)

# Lấy dữ liệu
d3 <- d3 %>% mutate(text_vector = mb_long %>%
                      as_vector() %>%
                      str_to_lower() %>% # Chuyển về chữ in thường
                      str_squish() %>%  # Xóa khoảng trống thừa giữa các ký tự
                      stri_trans_general(id = 'Latin-ASCII') # Xóa dấu của chữ
                    )

# -------------------------------
## Khoanh vùng liên quan đến m2
# -------------------------------
f1_dt <- function(text_vector){
  ## Tạo mẫu regrex
  match_m2 <- c("[:digit:]+\\s*m2", # vd:30m2, 30 m2
                  "[:digit:]+(\\.|,|x)[:digit:]+\\s*m2", # vd: 30.06m2, 30x06m2, 30,06m2
                  "[:digit:]+\\s*x\\s*[:digit:]+\\s*m2"# # vd: 30 x 9 m2
                  ) %>% paste0(collapse = '|')
   
  ## Xuất dữ liệu
    out <- text_vector %>% as_vector() %>%
      str_extract_all(pattern = match_m2, simplify = T)
 
  }
# -------------------------------
# Khoanh vùng liên quan đến dt hoặc diện tích
# -------------------------------
f2_dt <- function(x){
  ## Tạo mẫu regrex
  match_dt <- c("dt\\s*:\\s*\\d+\\s*x\\s*\\d+", # vd: dt: 3 x 5
                "dt\\s*:\\s*\\d+(\\.|,)\\d+\\s*x\\s*\\d+(\\.|,)\\d+" , # vd: dt: 3.4 x 5.6,
                "dt\\s*:\\s*\\d+\\s*x\\s*\\d+(\\.|,)?\\d*", #, # vd: dt: 3 x 5.6,
                "dt\\s*:\\s*\\d+(\\.|,)?\\d*\\s*x\\s*\\d+", #, # vd: dt: 3.4 x 5,
               
                "dien\\s*tich\\s*:\\s*\\d+\\s*x\\s*\\d+", # vd: dt: 3 x 5
                "dien\\s*tich\\s*:\\s*\\d+(\\.|,)\\d+\\s*x\\s*\\d+(\\.|,)\\d+" , # vd: dt: 3.4 x 5.6,
                "dien\\s*tich\\s*:\\s*\\d+\\s*x\\s*\\d+(\\.|,)?\\d*", #, # vd: dt: 3 x 5.6,
                "dien\\s*tich\\s*:\\s*\\d+(\\.|,)?\\d*\\s*x\\s*\\d+" #, # vd: dt: 3.4 x 5,
                ) %>% paste0(collapse = '|')
 
  ## Xuất dữ liệu
  out <- text_vector %>% as_vector() %>%
    str_extract_all(pattern = match_dt, simplify = T)

}



m2 <- d3 %>%
  filter(str_detect(text_vector, 'm2') == T) %>%
  select(text_vector)

non_m2 <- d3 %>%
  filter(str_detect(text_vector, 'm2') == F) %>%
  select(text_vector)

m2 <- f1_dt(m2)

non_m2 <- f2_dt(non_m2)