2017-08-14 44 views
1

例如,假设我想构建一个用于分析客户事务的包。在一个漂亮的世界里,每一个交易数据集看起来像处理具有相同数据类型但列名不同的数据集的最佳实践

TransactionId CustomerId TransactionDate 
1:    1   1  2017-01-01 
2:    2   2  2017-01-15 
3:    3   1  2017-05-20 
4:    4   3  2017-06-11 

然后,我可以做很好的功能,如

num_customers <- function(transactions){ 
    length(unique(transactions$CustomerId)) 
} 

在现实中,人们使用的列名会有所不同。 (例如,“CustomerId”,“CustomerID”和“cust_id”可能全部由不同的公司使用)。

我的问题是,我处理这个问题的最佳方法是什么?我计划在很大程度上依赖于data.table,所以我的直觉是做让用户我像

mytransactions <- data.table(
    transaction_id = c(1L, 2L, 3L, 4L), 
    customer_id = c(1L, 2L, 1L, 3L), 
    transaction_date = as.Date(c("2017-01-01", "2017-01-15", "2017-05-20", "2017-06-11")) 
) 
setattr(
    mytransactions, 
    name = "colmap", 
    value = c(TransactionID="transaction_id", CustomerID="customer_id", TransactionDate="transaction_date") 
) 
attributes(mytransactions) 

其表的属性。然而,不幸的是,一旦使用的人提供他们的列名的映射因为他们的数据子集,这个属性被删除。

attributes(mytransactions[1:2]) 
+0

编程时使用'data.frame'对象使用'transactions [[“CustomerId”]]'而不是'transactions $ CustomerId'。像这样,你可以让函数使用一个字符值作为参数。像'num_customers < - 函数(transactions,custid)'。 (顺便说一句,你的函数定义中有一个错字,它不是'''')。 –

+0

@RuiBarradas谢谢,但我不认为这是一个包含许多函数的包的实际解决方案,特别是因为它需要用户输入每个单一功能的列名映射。这可能会使用户的代码不必要的冗长和重复。 – Ben

+2

这是它的缺点,但它通常被认为是编程时最好的实践。建议'''操作符应该留给交互式使用而已。 –

回答

0

如果您希望数据具有特定形状和一组属性,请定义一个类。使用S3系统在R中很容易,因为您只需更改class属性。

让用户创建S3对象的最好方法是通过函数。为了保持适应现有数据集的原始“感觉”,让用户提供一个数据集并命名哪些列用于不同的值。默认的参数值可以保持您的软件包代码的简洁,并奖励尊重用户的标准。

transaction_table <- function(dataset, 
           cust_id = "CustomerId", 
           trans_id = "TransactionId", 
           trans_date = "TransactionDate") { 
    keep_columns <- c(
    CustomerId  = cust_id, 
    TransactionId = trans_id, 
    TransactionDate = trans_date 
) 
    out_table <- dataset[, keep_columns, with = FALSE] 
    setnames(out_table, names(keep_columns)) 
    setattr(out_table, "class", c("transaction_table", class(out_table))) 
    out_table 
} 


standardized <- transaction_table(
    mytransactions, 
    cust_id = "customer_id", 
    trans_id = "transaction_id", 
    trans_date = "transaction_date" 
) 
standardized 
# CustomerId TransactionId TransactionDate 
# 1:   1    1  2017-01-01 
# 2:   2    2  2017-01-15 
# 3:   1    3  2017-05-20 
# 4:   3    4  2017-06-11 

作为奖励,您现在可以充分利用S3系统,为泛型函数定义类特定的方法。

print.transaction_table <- function(x, ...) { 
    time_range <- range(standardized[["TransactionDate"]]) 
    formatted_range <- strftime(time_range) 
    cat("Transactions from", formatted_range[1], "to", formatted_range[2], "\n") 
    NextMethod() 
} 


print(standardized) 
# Transactions from 2017-01-01 to 2017-06-11 
# CustomerId TransactionId TransactionDate 
# 1:   1    1  2017-01-01 
# 2:   2    2  2017-01-15 
# 3:   1    3  2017-05-20 
# 4:   3    4  2017-06-11 
相关问题