jdeboer / ganalytics Goto Github PK
View Code? Open in Web Editor NEWInteract with Google Analytics using R
License: Other
Interact with Google Analytics using R
License: Other
Aim: To be able to use the ganalytics
expression language with googleAnalyticsR
. This is to take advantage of the Google Analytics Reporting API Version 4 interface made available from googleAnalyticsR
while also continuing support for ganalytics
expressions.
The following coercion functions have been tested and appear to result in mostly similar object structures with googleAnalyticsR
. I am yet to test whether those objects are then accepted by the googleAnalyticsR::google_analytics_4
function and whether that function still produces the expected outputs. If so, then the next step is to finish the definitions for these coercion functions to cover any remaining object classes.
metric_operators <- c(
"EQUAL" = "==",
"LESS_THAN" = "<",
"GREATER_THAN" = ">",
"BETWEEN" = "<>"
)
dimension_operators <- c(
"REGEXP" = "=~",
"PARTIAL" = "=@",
"EXACT" = "==",
"IN_LIST" = "[]",
"NUMERIC_LESS_THAN" = "<",
"NUMERIC_GREATER_THAN" = ">",
"NUMERIC_BETWEEN" = "<>"
)
negated_operators <- c(
"!=", "!~", "!@", ">=", "<="
)
setClass("dim_fil_ga4")
setClass("met_fil_ga4")
setClass("segmentFilterClause_ga4")
setClass("orFiltersForSegment_ga4")
setClass("segmentSequenceStep_ga4")
setClass("simpleSegment_ga4")
setClass("sequenceSegment_ga4")
setClass("segmentFilter_ga4")
setClass("segmentDef_ga4")
get_expression_details <- function(from, var_operators) {
varName <- as.character(Var(from))
names(varName) <- sub("^ga:", "", varName)
operator <- Comparator(from)
negated <- operator %in% negated_operators
if(negated) operator <- Not(operator)
operator_lookup_index <- match(as.character(operator), var_operators)
operator_name <- names(var_operators)[operator_lookup_index]
operand <- as.character(Operand(from))
expressions <- character(0)
minComparisonValue <- character(0)
maxComparisonValue <- character(0)
if(operator == "<>") {
minComparisonValue <- operand[1]
maxComparisonValue <- operand[2]
} else if(inherits(from, ".metExpr")) {
minComparisonValue <- operand
} else {
expressions <- operand
}
list(
varName = varName,
operator = operator,
operator_name = operator_name,
negated = negated,
expressions = expressions,
minComparisonValue = minComparisonValue,
maxComparisonValue = maxComparisonValue
)
}
setAs("gaDimExpr", "dim_fil_ga4", def = function(from, to) {
dim_operation <- get_expression_details(from, dimension_operators)
x <- list(
dimensionName = dim_operation$varName,
not = dim_operation$negated,
operator = dim_operation$operator_name,
expressions = as.list(as.character(Operand(from))),
caseSensitive = FALSE
)
class(x) <- "dim_fil_ga4"
x
})
setAs("gaMetExpr", "met_fil_ga4", def = function(from, to) {
met_operation <- get_expression_details(from, metric_operators)
x <- list(
metricName = met_operation$varName,
not = met_operation$negated,
operator = met_operation$operator_name,
comparisonValue = as.character(Operand(from))
)
class(x) <- "met_fil_ga4"
x
})
setAs("gaDimExpr", "segmentFilterClause_ga4", def = function(from, to) {
exp_details <- get_expression_details(from, dimension_operators)
segmentDimensionFilter <- list(
dimensionName = exp_details$varName,
operator = exp_details$operator_name,
caseSensitive = NULL,
expressions = exp_details$expressions,
minComparisonValue = exp_details$minComparisonValue,
maxComparisonValue = exp_details$maxComparisonValue
)
class(segmentDimensionFilter) <- "segmentDimFilter_ga4"
x <- list(
not = exp_details$negated,
dimensionFilter = segmentDimensionFilter,
metricFilter = NULL
)
class(x) <- "segmentFilterClause_ga4"
x
})
setAs("gaMetExpr", "segmentFilterClause_ga4", def = function(from, to) {
from <- as(from, "gaSegMetExpr")
as(from, to)
})
setAs("gaSegMetExpr", "segmentFilterClause_ga4", def = function(from, to) {
exp_details <- get_expression_details(from, metric_operators)
scope <- c("perHit" = "HIT", "perSession" = "SESSION", "perUser" = "USER")[[ScopeLevel(from)]]
segmentMetricFilter <- list(
scope = scope,
metricName = exp_details$varName,
operator = exp_details$operator_name,
comparisonValue = exp_details$minComparisonValue,
maxComparisonValue = exp_details$maxComparisonValue
)
class(segmentMetricFilter) <- "segmentMetFilter_ga4"
x <- list(
not = exp_details$negated,
dimensionFilter = NULL,
metricFilter = segmentMetricFilter
)
class(x) <- "segmentFilterClause_ga4"
x
})
setAs("orExpr", "orFiltersForSegment_ga4", def = function(from, to) {
x <- list(
segmentFilterClauses = lapply(from, as, "segmentFilterClause_ga4")
)
class(x) <- "orFiltersForSegment_ga4"
x
})
setAs("andExpr", "simpleSegment_ga4", def = function(from, to) {
x <- list(
orFiltersForSegment = lapply(from, as, "orFiltersForSegment_ga4")
)
class(x) <- "simpleSegment_ga4"
x
})
setAs("gaSegmentSequenceStep", "segmentSequenceStep_ga4", def = function(from, to) {
matchType <- if(from@immediatelyPrecedes) "IMMEDIATELY_PRECEDES" else "PRECEDES"
x <- c(
as(as(from@.Data, "andExpr"), "simpleSegment_ga4"),
list(matchType = matchType)
)
class(x) <- "segmentSequenceStep_ga4"
x
})
setAs("gaSegmentSequenceFilter", "sequenceSegment_ga4", def = function(from, to) {
segmentSequenceSteps <- lapply(from, as, "segmentSequenceStep_ga4")
x <- list(
segmentSequenceSteps = segmentSequenceSteps,
firstStepShouldMatchFirstHit = from[[1]]@immediatelyPrecedes
)
class(x) <- "sequenceSegment_ga4"
x
})
setAs("gaSegmentConditionFilter", "segmentFilter_ga4", def = function(from, to) {
x <- list(
not = IsNegated(from),
simpleSegment = as(from, "simpleSegment_ga4"),
sequenceSegment = NULL
)
class(x) <- "segmentFilter_ga4"
x
})
setAs("gaSegmentSequenceFilter", "segmentFilter_ga4", def = function(from, to) {
x <- list(
not = IsNegated(from),
simpleSegment = NULL,
sequenceSegment = as(from, "sequenceSegment_ga4")
)
class(x) <- "segmentFilter_ga4"
x
})
setAs("gaSegmentFilterList", "segmentDef_ga4", def = function(from, to) {
x <- list(
segmentFilters = lapply(from, as, "segmentFilter_ga4")
)
class(x) <- "segmentDef_ga4"
x
})
All user-level objects in a package (including S4 classes and methods) should have documentation entries
Hi.
In first thank you for this an interesting realisation GA APi access from R.
But seems now I can't get it worked. I follow instructions from README.
install_github(repo = "ganalytics", username = "jdeboer")
install.packages(c("plyr", "stringr", "RJSONIO", "Rook", "httpuv"))
then restart R-session.
library(ganalytics)
Sys.setenv(GANALYTICS_CONSUMER_ID = "myKey",
GANALYTICS_CONSUMER_SECRET = "mySecret")
ga.query <- GaQuery(profileID)
GetGaData(ga.query)
Error in GetGaData(ga.query) : could not find function "new_oauth"
I also trid pass key and secret to GetGaData
with same results.
Does I forgot about something?
Currently, the following functions will need to be reviewed against those requirements:
GoogleApiCreds
GaMetaUpdate
As per package development guidelines:
"Packages should not write in the users' home filespace, nor anywhere else on the file system apart from the R session's temporary directory (or during installation in the location pointed to by TMPDIR: and such usage should be cleaned up). Installing into the system's R installation (e.g., scripts to its bin directory) is not allowed.
Limited exceptions may be allowed in interactive sessions if the package obtains confirmation from the user.
Utilise the existing googleAuthR package by @MarkEdmondson1234 where possible. This way, the ganalytics package can be modularised into smaller packages, some of which could be reused by other Google Analytics related R packages.
E.g. "ga:nextPagePath" is deprecated, so Var("nextPagePath")
should give a warning, and so should new('gaDimVar', 'ga:nextPagePath')
Consider the class signature for this method as a gaView or gaProfileId, with perhaps an optional metric as the second argument with a default of "ga:sessions".
Could also be done similarly for GaEndDate and GaDateRange.
Consider using the creation date property of the gaView object as a starting point for lookup.
Consider implementing this for when a user sets the sortBy of query or coerces a query to a query string.
When I type ?Expr()
I get a no documentation for function 'Expr'
error. That is a function in the package, right? Should it have documentation available?
Fails to install:
---> Configuring R-ganalytics
Executing: cd "/opt/local/var/macports/build/_opt_PPCSnowLeopardPorts_R_R-ganalytics/R-ganalytics/work/ganalytics-0.10.7" && /opt/local/bin/R CMD build . --no-manual --no-build-vignettes --keep-empty-dirs
* checking for file ‘./DESCRIPTION’ ... OK
* preparing ‘ganalytics’:
* checking DESCRIPTION meta-information ... OK
* checking for LF line-endings in source and make files and shell scripts
* checking for empty or unneeded directories
Omitted ‘LazyData’ from DESCRIPTION
* building ‘ganalytics_0.10.7.tar.gz’
---> Building R-ganalytics
xinstall: mkdir /opt/local/var/macports/build/_opt_PPCSnowLeopardPorts_R_R-ganalytics/R-ganalytics/work/build
Executing: cd "/opt/local/var/macports/build/_opt_PPCSnowLeopardPorts_R_R-ganalytics/R-ganalytics/work/ganalytics-0.10.7" && /opt/local/bin/R CMD INSTALL . --library=/opt/local/var/macports/build/_opt_PPCSnowLeopardPorts_R_R-ganalytics/R-ganalytics/work/build --install-tests
* installing *source* package ‘ganalytics’ ...
** using staged installation
** R
** demo
** inst
** tests
** byte-compile and prepare package for lazy loading
in method for ‘coerce’ with signature ‘"gaSegmentSequenceFilter","json"’: no definition for class “json”
in method for ‘coerce’ with signature ‘"gaDynSegment","json"’: no definition for class “json”
in method for ‘coerce’ with signature ‘"gaDynSegment","json"’: no definition for class “json”
Error : in method for ‘SortBy’ with signature ‘object=".query"’: arguments (‘desc’, ‘type’) after ‘...’ in the generic must appear in the method, in the same place at the end of the argument list
Error: unable to load R code in package ‘ganalytics’
Execution halted
ERROR: lazy loading failed for package ‘ganalytics’
* removing ‘/opt/local/var/macports/build/_opt_PPCSnowLeopardPorts_R_R-ganalytics/R-ganalytics/work/build/ganalytics’
Command failed: cd "/opt/local/var/macports/build/_opt_PPCSnowLeopardPorts_R_R-ganalytics/R-ganalytics/work/ganalytics-0.10.7" && /opt/local/bin/R CMD INSTALL . --library=/opt/local/var/macports/build/_opt_PPCSnowLeopardPorts_R_R-ganalytics/R-ganalytics/work/build --install-tests
Exit code: 1
Error: Failed to build R-ganalytics: command execution failed
I am having a difficult time getting this package to install using devtools
.
I keep getting the same error using the latest versions of R and Rstudio
oauth_listener() needs an interactive environment
Any help is appreciated as I was able to install other packages with devtools:install_github()
as per guidelines described by .Deprecated()
"The original help page for these functions is often available at help("oldName-deprecated") (note the quotes). Functions should be listed in help("pkg-deprecated") for an appropriate pkg, including base."
Implement an optional re-sampling technique to take the reported sample rate and if not NaN or not NA or not 100% but a number greater than 0 and less than 1, then use this to split the date range further if not already at daily level.
In the request:
Determine what (if any) changes need to be made to the R scripts that process the response with httr.
Maximum of 1000 calls in a single batch request
The Core Reporting API is limited to 10 concurrent requests per view
For example:
Segment(Expr(~pagepath %matches% "products")) & Segment(Expr(~source == "google"))
Should be equivalent to:
Segment(Include(Expr(~pagepath %matches% "products")), Include(Expr(~source == "google")))
query <- GaQuery()
Metrics(query) <- c("users", "sessions", "pageviews", "bounceRate", "timeOnSite", "goalCompletionsAll", "transactions", "transactionRevenue", "totalEvents", "uniquePageviews", "goal1Completions", ...)
metrics <- Metrics(query)
dimensions <- Dimensions(query)
kMaxApiQueryMetrics <- 10
metricGroups <- split(metrics, ceiling(seq_along(metrics) / kMaxApiQueryMetrics))
responseDataFramesList <- lapply(metricGroups, function(queryMetrics) {
Metrics(query) <- queryMetrics
GetGaData(query)
})
response <- Reduce(function(x, y) {join(x, y, by = dimensions)}, responseDataFramesList)
Taking an example from http://www.slideshare.net/johanndeboer/web-analytics-with-r-melb-urn:
GaAnd(
GaExpr('keyword', '@', 'buy'),
GaOr(
GaExpr('city', '~', '^(Sydney|Melbourne)$'),
GaExpr('isTablet', '=', ‘Yes’) ) )
it would be relatively straightforward to allow you to write
GaExpr('keyword', '@', 'buy') &&
(GaExpr('city', '~', '^(Sydney|Melbourne)$') ||
GaExpr('isTablet', '=', ‘Yes’))
just by adding the appropriate methods for &&
and ||
.
But I think it would be relatively straightforward to go even further and be able to write
GaAutoExpr(keyword %matches% "buy" &&
(city %in% c("Sydney", "Melbourne") || isTablet == TRUE))
using the principles described in http://adv-r.had.co.nz/dsl.html.
One approach to consider is this which has been proposed for the RGoogleAnalytics package as a pull request
Executing GaExpr("ga:date", "==", "2013-06-01")
results in the following error message shown in the R console:
Error in if (ValidGaOperand(object@gaVar, object@gaOperand)) { :
"argument is not interpretable as logical"
Assert: "Date range for user-based segments must not exceed 90 days."
Example of a proposed idea for expressing a sequence:
segment(
perUser(
expr1, # treat an expression as 'condition type segment filter' by default
perHit(
metrixExpr1
)
),
sequence(
epxr2,
then(expr3), # 'then' means 'immediately followed by'
later(expr4) # 'later' means 'followed by', but not necessarily immediately.
),
sequence(
first(expr5), # First expressly means 'first interaction' within the date range.
then(expr6), # By default, treat an expression within a sequence as happening
expr7 # at any point after any preceding steps in the sequence, i.e. 'later'.
)
)
Keep within the ganalytics namespace and do not export
Set each time the GoogleApiCreds() function is used.
Used by GoogleApiCreds if the global variable has already been defined.
May be related to incorrect call back URL being used when user creates OAuth credentials
Using google JWT.
i.e. in node js googleapis
it works like that:
var google = require('googleapis');
var analytics = google.analytics({
version: 'v3'
});
var jwtClient = new google.auth.JWT(
config.ga.client_email,
null,
config.ga.private_key, ['https://www.googleapis.com/auth/analytics.readonly'],
null)
Then you can access your data as follow:
analytics.get({
'ids': 'ga:123456789',
'start-date': timestamp_start,
'end-date': timestamp_start,
'metrics': 'ga:sessions',
'dimensions': 'ga:socialActivityContentUrl',
'sort': '-ga:sessions',
'max-results': 10000,
auth: jwtClient
})
Therefore, you only need an email and private key and it does the rest for you (no need to auth via a webpage).
e.g. gaid::aJzQie3iR9OF4aYr4fMI0g
For set your system environment variables you can use Sys.setenv(GANALYTICS_CONSUMER_ID = "<Your client ID>", GANALYTICS_CONSUMER_SECRET = "<Your client secret>")
. Also you can use .Renviron
on unix-like systems.
For example a Query cannot use the experimentId, experimentVariant dimensions
GaDimensions(gaQuery) <- c("date","experimentId")
Error in validObject(.Object) :
invalid class “gaDimVar” object: Invalid GA dimension name: experimentId
Refer to IsVarMatch function used for validation of dimension and metric objects: https://github.com/jdeboer/ganalytics/blob/master/R/all-classes.R#L11
Also, the initialisation method for dimension and metric objects: https://github.com/jdeboer/ganalytics/blob/master/R/init-methods.R#L25
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.