2015-04-21 17 views
15

Câu hỏi của tôi liên quan đến cách tạo biến mới trên khung dữ liệu trong R dựa trên kết quả của cụm từ thông dụng. Dưới đây là một ví dụ nhỏ nhất của dữ liệu:tạo biến mới dựa trên cụm từ thông dụng

df <- data.frame(model=c("Legacy 2.0 BG5 B4 AUTO","Legacy 2.0 BH5 AT","Legacy 2.0i CVT Non Leather","Legacy 2.0i CVT","Legacy 2.0 BL5 AUTO B4", 
       "Legacy 2.0 BP5 AUTO","Legacy 2.0 BM5 AUTO CVT"), CRSP=c(3450000,3365000,4950000,5250000,4787526,3550000,5235000)) 

df 
         model CRSP 
1  Legacy 2.0 BG5 B4 AUTO 3450000 
2   Legacy 2.0 BH5 AT 3365000 
3 Legacy 2.0i CVT Non Leather 4950000 
4    Legacy 2.0i CVT 5250000 
5  Legacy 2.0 BL5 AUTO B4 4787526 
6   Legacy 2.0 BP5 AUTO 3550000 
7  Legacy 2.0 BM5 AUTO CVT 5235000 

Tôi muốn tạo ra một biến 'khung' mới có giá trị là yếu tố thứ ba của 'mô hình' tương ứng với biến chuỗi, do đó kết thúc với:

df 
         model CRSP chassis 
1  Legacy 2.0 BG5 B4 AUTO 3450000  BG5 
2   Legacy 2.0 BH5 AT 3365000  BH5 
3 Legacy 2.0i CVT Non Leather 4950000  CVT 
4    Legacy 2.0i CVT 5250000  CVT 
5  Legacy 2.0 BL5 AUTO B4 4787526  BL5 
6   Legacy 2.0 BP5 AUTO 3550000  BP5 
7  Legacy 2.0 BM5 AUTO CVT 5235000  BM5 

tôi cần phải tìm một cách để trích xuất các yếu tố thích hợp trong mỗi hàng và đặt chúng trong biến mới. Bất kỳ hỗ trợ nào sẽ được đánh giá cao.

Trả lời

5

Tôi là một fan hâm mộ lớn của tidyr cho điều này loại công việc và giải nén tất cả các mảnh thành các cột riêng biệt:

if (!require("pacman")) install.packages("pacman") 
pacman::p_load(dplyr, tidyr) 

regx <- "(^[A-Za-z]+\\s+[0-9.a-z]+)\\s+([A-Z0-9]+)\\s*(.*)" 

df %>% 
    extract(model, c("a", "chassis", "b"), regx, remove=FALSE) 

##       model   a chassis   b CRSP 
## 1  Legacy 2.0 BG5 B4 AUTO Legacy 2.0  BG5  B4 AUTO 3450000 
## 2   Legacy 2.0 BH5 AT Legacy 2.0  BH5   AT 3365000 
## 3 Legacy 2.0i CVT Non Leather Legacy 2.0i  CVT Non Leather 4950000 
## 4    Legacy 2.0i CVT Legacy 2.0i  CVT    5250000 
## 5  Legacy 2.0 BL5 AUTO B4 Legacy 2.0  BL5  AUTO B4 4787526 
## 6   Legacy 2.0 BP5 AUTO Legacy 2.0  BP5  AUTO 3550000 
## 7  Legacy 2.0 BM5 AUTO CVT Legacy 2.0  BM5 AUTO CVT 5235000 

Bạn có thể nhận chung chung hơn một chút với regex này:

regx <- "(^[^ ]+\\s+[^ ]+)\\s+([^ ]+)\\s*(.*)" 

Cũng lưu ý bạn có thể sử dụng extract để có được chỉ là cột bạn sau bởi thả dấu ngoặc đơn nhóm vào nhóm đầu tiên và nhóm cuối cùng như sau:

regx <- "^[A-Za-z]+\\s+[0-9.a-z]+\\s+([A-Z0-9]+)\\s*.*" 

df %>% 
    extract(model, "chassis", regx, remove=FALSE) 
+2

Tôi có các bước thao tác dữ liệu khác và các bước thao tác dữ liệu tiếp theo trên cùng một khung dữ liệu trong một ống ** dplyr ** '%>%' và vì vậy giải pháp này thuận tiện hơn vì tôi có thể chèn trực tiếp vào vòng lặp. Cảm ơn @TylerRinker – amo

4

Chúng tôi có thể khớp với ký tự cho đến phần số bao gồm i và dấu cách, thay thế bằng '' bằng cách sử dụng sub và sau đó trích xuất từ ​​đầu tiên bằng word.

library(stringr) 
word(sub('^\\D*[0-9.i ]*', '', df$model),1) 
#[1] "BG5" "BH5" "CVT" "CVT" "BL5" "BP5" "BM5" 

Hoặc phù hợp với không gian, thay thế với một không gian duy nhất và sử dụng word

word(gsub(' +', ' ', df$model),3) 
#[1] "BG5" "BH5" "CVT" "CVT" "BL5" "BP5" "BM5" 

LƯU Ý: Không chắc không gian thêm trong phần tử đầu tiên của 'mô hình' là một lỗi đánh máy. Nếu tập dữ liệu gốc không có nhiều khoảng trống giữa các từ, thì word(df$model, 3) sẽ hoạt động.

10

Dưới đây là một giải pháp có thể sử dụng stringi

library(stringi) 
df$chassis <- stri_extract_all_words(df$model, simplify = TRUE)[, 3] 
df 
#       model CRSP chassis 
# 1  Legacy 2.0 BG5 B4 AUTO 3450000  BG5 
# 2   Legacy 2.0 BH5 AT 3365000  BH5 
# 3 Legacy 2.0i CVT Non Leather 4950000  CVT 
# 4    Legacy 2.0i CVT 5250000  CVT 
# 5  Legacy 2.0 BL5 AUTO B4 4787526  BL5 
# 6   Legacy 2.0 BP5 AUTO 3550000  BP5 
# 7  Legacy 2.0 BM5 AUTO CVT 5235000  BM5 

Hoặc tương tự

df$chassis <- sapply(stri_extract_all_words(df$model), `[`, 3) 
5

Một giải pháp thay thế sử dụng strsplit

# Split each of the models using space (the + accounts for multiple spaces) 
# Note that model is a factor in your data frame, so it must be cast to char 
model.split <- strsplit(as.character(df$model), " +") 
# Now go through each element of the splitted list and get the 3rd word 
df$chassis <- sapply(model.split, function(x){x[3]}) 
+2

Hoặc một cách tiếp cận tương tự như sử dụng 'data.table'. 'setDT (df) [, chassis: = tstrsplit (model, '+') [[3]]] []' – akrun

2

Bạn có thể chia nhỏ ký tự khoảng trắng bằng cách sử dụng cSplit từ splitstackshape gói:

library(splitstackshape) 
df$chassis <- cSplit(df, "model", sep = " ", "wide")$model_3 

Điều này tránh sự cần thiết cho một regex hoặc một apply chức năng.

+0

'cSplit' có tùy chọn 'drop = FALSE' và trả về dữ liệu. Vì vậy, có thể điều này cũng sẽ hoạt động 'cSplit (df," model ", sep =" "," wide ", drop = FALSE) [, c (1,5), with = FALSE]' – akrun

3

này có thể dễ dàng được thực hiện trong cơ sở R:

transform(df, chassis=sub("^(\\S+\\s+){2}(\\S+).*", "\\2", model)) 

sản xuất:

     model CRSP chassis 
1  Legacy 2.0 BG5 B4 AUTO 3450000  BG5 
2   Legacy 2.0 BH5 AT 3365000  BH5 
3 Legacy 2.0i CVT Non Leather 4950000  CVT 
4    Legacy 2.0i CVT 5250000  CVT 
5  Legacy 2.0 BL5 AUTO B4 4787526  BL5 
6   Legacy 2.0 BP5 AUTO 3550000  BP5 
7  Legacy 2.0 BM5 AUTO CVT 5235000  BM5  
Các vấn đề liên quan