Create a S4 super class - with code example - r

Okay, it took me a while to create a snippet of code that replicates my problem. Here it is. Notice that if you run the command new("FirstSet", id = "Input", multiplier = 2)
you will get the correct answer. However, if you try to create a class that contains both you will get the following: Error in .local(.Object, ...) : argument "id" is missing, with no default. This is literally the best I can do to explain/show the problem.
What in the world am I doing wrong?
setClass("Details",
representation(
ID = "character",
Anumber = "numeric"))
Input <- new("Details",
ID = "Input",
Anumber = 2)
setClass("FirstSet",
representation(
Anothernumber = "numeric"))
setGeneric(
name = "FirstSet",
def = function(object){standardGeneric("FirstSet")}
)
setMethod("initialize",
signature(.Object = "FirstSet"),
function (.Object, id, multiplier)
{ x = id#Anumber
y = x * multiplier
.Object#Anothernumber = y
return(.Object)
}
)
setClass("Super", contains = c("Details", "FirstSet"))
Corrected Code now gives a new error. I followed the instruction in the post and solved my problem. I also created a generic and a method for "Super", see code below,. Now, I get a new error. Error in .local(.Object, ...) : trying to get slot "Anumber" from an object of a basic class ("character") with no slots. Man, this is exhausting, I thought I had it.
The goal for details is, there will be many files that are serialized and methods are called depending on characteristics of the data in the file. Is this even possible in R or am I trying to do something that R cannot do?
New Code
setClass("Details",
representation(
ID = "character",
Anumber = "numeric"))
setGeneric("Details",
def = function(object){standardGeneric("Details")})
setMethod("initialize",
signature(.Object = "Details"),
function(.Object, ID = character(), Anumber = numeric()){
.Object#ID = ID
.Object#Anumber = 2
return(.Object)
})
setClass("FirstSet",
representation(
Anothernumber = "numeric"))
setGeneric(
name = "FirstSet",
def = function(object){standardGeneric("FirstSet")}
)
setMethod("initialize",
signature(.Object = "FirstSet"),
function (.Object, id = character(), multiplier = numeric())
{ x = id#Anumber
y = x * multiplier
.Object#Anothernumber = y
return(.Object)
}
)
setClass("Super", contains = c("Details", "FirstSet"))
setGeneric("Super",
def = function(object){standardGeneric("Super")})
setMethod("initialize",
signature(.Object = "Super"),
function(.Object, id = character(), Anumber = numeric()){
Details <- new("Details", ID = id, Anumber = Anumber)
FirstSet <- new("FirstSet", Anothernumber = Anothernumber)
Super <- new("Super", Details, FirstSet)
return(.Object)
})

The basic rule is that new("FirstSet") (or any non-virtual class) needs to work. Yours doesn't (because the intiailize arguments don't have default values). See this answer for some more guidelines.

Related

Issue scraping flairs from Reddit: Arguments imply differing number of rows?

I'm trying to scrape a subreddit using a RedditExtractoR library that I've modified, but I keep running into this error. I modified the get_thread_content.R file in the source code so that it looks like this:
#' Get thread contents of Reddit URLs
#'
#' This function takes a collection of URLs and returns a list with 2 data frames:
#' 1. a data frame containing meta data describing each thread
#' 2. a data frame with comments found in all threads
#'
#' The URLs are being retained in both tables which would allow you to join them if needed
#'
#' #param urls A vector of strings pointing to a Reddit thread
#' #return A list with 2 data frames "threads" and "comments"
#' #export
get_thread_content <- function(urls){
data <- lapply(urls, parse_thread_url)
list(
threads = lapply(data, function(z) z[["thread"]]) |> rbind_list(),
comments = lapply(data, function(z) z[["comments"]]) |> remove_na() |> rbind_list()
)
}
# Build a data frame with thread attributes of interest
build_thread_content_df <- function(json, request_url) {
if (is.null(json$link_flair_text))
{thread_flair_info <- 'no flair'}
else {thread_flair_info <- json$link_flair_text}
if (is.null(json$author_flair_text))
{author_flair_info <- 'no flair'}
else {author_flair_info <- json$author_flair_text}
df <- data.frame(
url = strip_json(request_url),
author = json$author,
author_flair_text = author_flair_info,
date = timestamp_to_date(json$created_utc),
timestamp = json$created_utc,
title = json$title,
text = json$selftext,
thread_flair = thread_flair_info,
subreddit = json$subreddit,
score = json$score,
upvotes = json$ups,
downvotes = json$downs,
up_ratio = json$upvote_ratio,
total_awards_received = json$total_awards_received,
golds = json$gilded,
cross_posts = json$num_crossposts,
comments = json$num_comments,
stringsAsFactors = FALSE
)
return(df)
}
nullfix <- function(x){
if(is.null(x))
{x <- "no flair"}
else {x}
}
# Build a data frame with comments and their attributes.
build_comments_content_df <- function(json, request_url) {
data.frame(
url = strip_json(request_url),
author = extract_comments_attributes(json, "author"),
comment_author_flair = nullfix(extract_comments_attributes(json, "author_flair_text")),
date = extract_comments_attributes(json, "created_utc") |> timestamp_to_date(),
timestamp = extract_comments_attributes(json, "created_utc"),
score = extract_comments_attributes(json, "score"),
upvotes = extract_comments_attributes(json, "ups"),
downvotes = extract_comments_attributes(json, "downs"),
golds = extract_comments_attributes(json, "gilded"),
comment = extract_comments_attributes(json, "body"),
comment_id = build_comment_ids(json),
stringsAsFactors = FALSE
)
}
Everything works except the comment_author_flair part. I initially tried using similar code to what I used for the get_thread_content function, but that failed, so I separated out the function (see: nullfix) and tried to apply it to the basic code, but that still isn't working, as I get the same error.
As a reproducable example, after modifying that library:
thread <- get_thread_content("https://www.reddit.com/r/SSBM/comments/10ys20y/who_were_the_least_clutch_players/")
I would expect to get 69 flair values with this code, one for each comment, with NULL values replaced by "no flair" because of the nullfix function. Instead I get the error:
Error in data.frame(url = strip_json(request_url), author = extract_comments_attributes(json, :
arguments imply differing number of rows: 1, 69, 29

R: Collect All Function Definitions from a Library

I am working with R. I found this previous post on stackoverflow which shows how to get a "list" of all functions that belong to a given library:
How to find all functions in an R package?
For example:
#load desired library
library(ParBayesianOptimization)
#find out all functions from this library
getNamespaceExports("ParBayesianOptimization")
[1] "addIterations" "getLocalOptimums" "bayesOpt" "getBestPars" "changeSaveFile" "updateGP"
The above code tells me the name of all functions that are used in the "ParBayesianOptimization" library. From here, I could manually inspect each one of these functions - for example:
# manually inspect any one of these functions
getAnywhere(bayesOpt)
A single object matching ‘bayesOpt’ was found
It was found in the following places
package:ParBayesianOptimization
namespace:ParBayesianOptimization
with value
#function stats here
function (FUN, bounds, saveFile = NULL, initGrid, initPoints = 4,
iters.n = 3, iters.k = 1, otherHalting = list(timeLimit = Inf,
minUtility = 0), acq = "ucb", kappa = 2.576, eps = 0,
parallel = FALSE, gsPoints = pmax(100, length(bounds)^3),
convThresh = 1e+08, acqThresh = 1, errorHandling = "stop",
plotProgress = FALSE, verbose = 1, ...)
{
startT <- Sys.time()
optObj <- list()
etc etc etc ...
saveFile = saveFile, verbose = verbose, ...)
return(optObj)
}
#function ends here
<bytecode: 0x000001cbb4145db0>
<environment: namespace:ParBayesianOptimization>
Goal : Is it possible to take each one of these functions and create a notepad file with their full definitions?
Something that would look like this:
My attempt:
I thought I could first make an "object" in R that contained all the functions found in this library:
library(plyr)
a = getNamespaceExports("ParBayesianOptimization")
my_list = do.call("rbind.fill", lapply(a, as.data.frame))
X[[i]]
1 addIterations
2 getLocalOptimums
3 bayesOpt
4 getBestPars
5 changeSaveFile
6 updateGP
Then, I could manually create an "assignment arrow":
header_text <- rep("<-")
Then, "paste" this to each function name:
combined_list <- as.character(paste(my_list, header_text, sep = ""))
But this is not looking correct:
combined_list
[1] "c(\"addIterations\", \"getLocalOptimums\", \"bayesOpt\", \"getBestPars\", \"changeSaveFile\", \"updateGP\")<- "
The goal is to automate the process of manually copying/pasting :
function_1 = getAnywhere("first function ParBayesianOptimization library")
function_2 = getAnywhere("second function ParBayesianOptimization library")
etc
final_list = c(function_1, function_2 ...)
And removing the generic description from each function:
A single object matching ‘bayesOpt’ was found
It was found in the following places
package:ParBayesianOptimization
namespace:ParBayesianOptimization
with value
In the end, if I were to "call" the final_list object, all the functions from this library should get recreated and reassigned.
Can someone please show me how to do this?
Thanks
You can use the dump function for this
pkg <- "ParBayesianOptimization"
dump(getNamespaceExports(pkg), file="funs.R", envir = asNamespace(pkg))
This code will help you write the function definitions of all the functions in a library to a text file.
fn_list <- getNamespaceExports("ParBayesianOptimization")
for(i in seq_along(fn_list)) {
header <- paste('\n\n####Function', i, '\n\n\n')
cat(paste0(header, paste0(getAnywhere(fn_list[i]), collapse = '\n'), '\n\n'),
file = 'function.txt', append = TRUE)
}

problems with UDpipe models

I'm trying to implement a sentiment analysis study on data extracted from Twitter, with R.
I am using the udpipe library
when I write
udpipe_dowload_model("model")
model< <- udpipe_load_model("directory)
out <- as.data.frame(udpipe_annotate(object, x, doc_id,...)
and I run, an exception is raised:
Error in udp_tokenise_tag_parse(object$model, x, doc_id, tokenizer, tagger, :
external pointer is not valid
the relative traceback is:
4.
stop(structure(list(message = "external pointer is not valid",
call = udp_tokenise_tag_parse(object$model, x, doc_id, tokenizer,
tagger, parser, log_every, log_now), cppstack = structure(list(
file = "", line = -1L, stack = c("1 udpipe.so 0x0000000117ba907e _ZN4Rcpp9exceptionC2EPKcb + 222", ...
3.
udp_tokenise_tag_parse(object$model, x, doc_id, tokenizer, tagger,
parser, log_every, log_now)
2.
udpipe_annotate(model, x = x, doc_id = doc_id, trace = F) at textAnalysisFunct.R#221
1.
lemmaUDP(x = twt$text_clean, model = modelI, doc_id = twt$doc_id,
stopw = tm::stopwords("italian"), userstopw = mystop)
then I started to debug and on the console appeared:
Error during wrapup: external pointer is not valid
the function lemmaUDP was created by my teacher, if useful I paste here its definition as well, but is the same as if done manually
lemmaUDP <- function(x = NULL,
model = NULL,
doc_id = NULL,
stopw = tm::stopwords("italian"),
userstopw=NULL){
require(udpipe)
if(is.null(x)){message("manca vettore testi");return()}
if(is.null(model)){message("manca modello");return()}
if(class(x) != "character"){message("il vettore x non è di tipo testo");return()}
if(class(model) != "udpipe_model"){message("modello non valido");return()}
if(is.null(doc_id)){doc_id <- 1:length(x)}
if(!is.null(userstopw)){
stopw <- c(stopw,userstopw)
}
xx <- udpipe_annotate(model, x = x, doc_id = doc_id,trace = F)
xx <- as.data.frame(xx)
xx$STOP <- ifelse(xx$lemma %in% stopw | xx$token %in% stopw,TRUE,FALSE)
return(xx)
}

R refClass Methods

I am using R refClass example below.
Person = setRefClass("Person",fields = list(name = "character", age = "numeric")
) ## Person = setRefClass("Person",
Person$methods = list(
increaseAge <- function(howMuch){
age = age + howMuch
}
)
When I store this program in a file called Person.R and source it, it does not show any errors. Now I instantiate a new object.
p = new("Person",name="sachin",age=40)
And I try to invoke the method increaseAge, using p$increaseAge(40), and it shows the following error
Error in envRefInferField(x, what, getClass(class(x)), selfEnv) :
"increaseAge" is not a valid field or method name for reference class "Person"
I cannot figure out why it says that the method increaseAge is not a valid method name when I have defined it.
To specify a method independent of class definition, invoke the methods() function on the generator. Also, use either <<- or .self$age = for the assignment.
Person$methods(increaseAge=function(howMuch) {
age <<- age + howMuch
## alterenatively, .self$age = age + howMuch or .self$age <- age + howMuch
})
Remember that R works best on vectors, so think of a Persons class (modeling columns) representing all the individuals in your study, rather than a collection of Person instances (modeling rows).
I get an error using your code. I would do something like this:
Person = setRefClass("Person",
fields = list(name = "character", age = "numeric"),
methods = list(
increaseAge = function(howMuch) age <<- age + howMuch
))
> p = new("Person",name="sachin",age=40)
> p$increaseAge(5)
> p$age
[1] 45

Define particular slot as separate class R

My aim is to define one of the slots of class Security as another class Quote.
First I define class Quote:
Quote <- setClass("Quote", slots = c(Last = "numeric", Settle = "numeric"))
Then I am trying to define class Security as following:
Security <- setClass("Security", slots = c(Name = "character", Price = "Quote"))
Finally I am trying to create constructor for class Security:
Security <- function(Name = character(), Last = numeric(), Settle = numeric())
new("Security", Name = Name, Price#Last = Last, Price#Settle = Settle)
Unfortunately, this code doesn't work...
Thanks in advance.
If offering the user a constructor named Security, make sure the default constructor is named differently
.Security <- setClass("Security", slots = c(Name = "character", Price = "Quote"))
In your own constructor, create the slot instance as an argument to default constructor; use ... to allow for class inheritance
Security <-
function(Name = character(), Last = numeric(), Settle = numeric(), ...)
{
.Security(Name=Name, Price=Quote(Last=Last, Settle=Settle), ...)
}
I'm still trying to learn S4, and I see that a recognized expert has already given an answer, so I'm mostly posting this as an example for critique:
.Quote <- setClass("Quote", slots = c(Last = "numeric", Settle = "numeric"))
.Security <- setClass("Security", slots = c(Name = "character", Price = "Quote"))
aNewSecurity <- .Security(Name = "newSec",
Price = .Quote(Last =20, Settle = 40) )
aNewSecurity
An object of class "Security"
Slot "Name":
[1] "newSec"
Slot "Price":
An object of class "Quote"
Slot "Last":
[1] 20
Slot "Settle":
[1] 40
I'm not sufficiently knowledgeable to know if separating Quote items from Security items is needed in this domain.

Resources