在R中从data.frame创建新的类

4
我在R中尝试使用函数、类和方法。为了有一个"手动"练习,也可以有用,我决定创建一个管理家庭预算的"包"。简而言之,我想要一系列的函数、类和方法来计算各种东西,绘制不同类型的图表等。我想做的第一件事是创建一个"Budget"类:它应该接收具有特定列的csv,并返回一个继承数据框相同方法的对象"Budget",但我可以对其应用一组"Budgets"方法。下面是我的想法。
prepareData = function (csv, type=1) {

if (type == 1) {
Data = read.csv(csv,dec = ".")}
else if (type == 2) {
Data = read.csv2(csv,dec = ",")}
else {stop ("Accetable value for type are 1 and 2")}

NamesToHave = c("Date","Title","Amount","Category")

if (sum(as.numeric(colnames(Data) %in% NamesToHave)) < 4) {
    stop ("The csv file has not the mandatory columns (Data, Title, Amount, Category)")}




if (class(try(tolower(Data$Title),silent = T)) == "try-error" | class(try(tolower(Data$Category),silent = T)) == "try-error") {
    stop("Are you sure there are no special character in your csv file ?")} 

Data$Day = sapply(strsplit(as.character(Data$Date), "/"),"[[",1)
Data$Month = month.abb[as.numeric(sapply(strsplit(as.character(Data$Date), "/"),"[[",2))]
Data$Year = sapply(strsplit(as.character(Data$Date), "/"),"[[",3)

Data = Data[with(Data, order(Year, Month, Day)), ]
Data$Amount = as.character(Data$Amount)
Data$Amount = as.numeric(as.character(Data$Amount))

class(Data) <- append(class(Data),"Budget")
return(Data)
}

现在,这将返回一个带有所有必要修改的数据框,并且作为函数总体上运行良好,但如果我采取以下csv文件,结果将不会如预期。
structure(list(Date = structure(c(22L, 1L, 1L, 1L, 1L, 1L), .Label = c("01/10/2016", 
"01/11/2016", "02/10/2016", "04/10/2016", "04/11/2016", "05/10/2016", 
"05/11/2016", "06/10/2016", "06/11/2016", "07/10/2016", "08/10/2016", 
"08/11/2016", "09/10/2016", "09/11/2016", "10/10/2016", "10/11/2016", 
"11/10/2016", "12/11/2016", "14/10/2016", "16/10/2016", "18/10/2016", 
"20/09/2016", "20/10/2016", "21/10/2016", "22/09/2016", "22/10/2016", 
"23/09/2016", "23/10/2016", "25/09/2016", "25/10/2016", "26/09/2016", 
"26/10/2016", "27/10/2016", "28/10/2016", "29/10/2016", "30/10/2016"
), class = "factor"), Title = structure(c(20L, 6L, 36L, 29L, 
30L, 11L), .Label = c("Bagpiper", "beer debaser", "Br", "brewdog", 
"Burger King", "Clas", "coop", "Coop", "Eriksdalbadet", "etc", 
"ETC", "Flippin", "Fotografiska", "Gateau Agneta", "Grekisk fastfood", 
"Grill", "Gunnarson", "Gunnarsson", "hemkop", "HK", "Hotorhallen", 
"ICA", "ICA Skinnskat", "Igor Sport", "Intersport", "Kak", "klattercentret", 
"LullesFagel", "Mae Thai", "MamaWolf", "Material", "Matrerial", 
"Oriental Supermarket", "Paradiset", "Pendeltag Uppsala", "PGW", 
"Pressbyran", "Primeburger", "Primo Ciao ciao", "R Asia", "Systembolaget", 
"taxi Skinnskat", "The Cure drinks", "Udden pensionat", "Ugglan", 
"Wentzels hobby"), class = "factor"), Amount = c(167.27, 331, 
971, 99, 192, 3289), Category = structure(c(10L, 3L, 3L, 6L, 
6L, 3L), .Label = c("Drink", "extra", "Extra", "Extra_Fede", 
"extra_food", "Extra_food", "extra_laure", "Extra_Laure", "food", 
"Food"), class = "factor")), .Names = c("Date", "Title", "Amount", 
"Category"), row.names = c(NA, 6L), class = "data.frame")

我运行

Data = prepareData("name.csv")
class(Data)

输出只是"data.frame"。但如果我从终端再次运行函数倒数第二行的代码,则可以得到正确结果。
class(Data) <- append(class(Data),"Budget")
class(Data)

我得到了"data.frame"和"Budget"作为输出。 我做错了什么?

我无法重现您的问题,因为您发布的示例存在几个问题。请查看此文章:http://stackoverflow.com/help/mcve。 - Tomás Barcellos
我也无法重现你的问题,该对象似乎具有正确的类。 - sebastian-c
我知道,很奇怪的是,当我修复一个无关的问题(请参见下面的答案)时,问题就被解决了。正如Tomas所说,有时重新启动R可能会有帮助。 - Federico Nemmi
1个回答

2
您的问题出在这里:

if (as.numeric(colnames(Data) %in% NamesToHave) != 4) {}

第一个比较将被向量化执行并返回TRUE TRUE TRUE TRUE,当经过as.numeric()时,它将变为1 1 1 1。然后,此向量将与!= 4进行比较,这是向量化执行的,并返回TRUE TRUE TRUE TRUE(所有“一”都与四不同)。if()语句不会评估整个向量,只会评估其第一个元素(并向您发出警告消息)。
要解决此问题,您只需将as.numeric()函数切换为sum()即可。
if (sum(colnames(Data) %in% NamesToHave) != 4) {}

当你对逻辑向量求和时,R会将其强制转换为数字:所有TRUE变为1,所有FASLE变为0。现在,你将得到4个总和,在if语句中评估为FALSE,函数将平稳运行。一旦我解决了它,当我第一次运行它时,它就有了两个类。
正如这篇文章所说的那样,在发布问题之前重新启动R,确保你仍然遇到了你要报告的问题。

谢谢,事实上当我在纠正我的示例时,我也发现了同样的问题。 然而,作为后续和提高自己的方式:在您看来,使这成为最小可重现示例缺少什么? 我放入了数据和代码,我还能做得更好吗? 无论如何,再次感谢! - Federico Nemmi
我们并不需要知道你在函数之前处理的每个情况(所有那些if-else语句)。实际上,如果你在发布问题之前将它们删除,你会意识到问题不在于分配类,而在于处理可能出现的错误。 - Tomás Barcellos
好的,明白了。谢谢您的反馈! - Federico Nemmi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接