3 Computational Quandaries
After gaining confidence in one’s data (or, at least, making peace with it), the next step in a data analysis is often to start cleaning and exploring that data with summary statistics, plots, and models. Generally, this requires a computational tool like SQL, R, or python.
The process of computation itself can be fraught with challenges. Computational tools are extremely literal; they are excellent at doing precisely what they were told to do but not often what analysts might have meant or wished that they would do. Additionally, the moment an analyst begins to use a tool, the conversation is no longer between them and the data; suddenly, the mental model of how every single tool developer thought you might want to do analysis affects the tools’ behaviors and the analysts’ results.
In this chapter, we will explore common ways that tools may do something technically correct, reasonable, and as-intended but very much not what analysts may expect. Along the way, we will see how computational methods interact with the data encoding choices we discussed in Chapter 2 (Data Dalliances).
3.1 Preliminaries - Data Computation
Before we think about specific tools or failure modes, we can first consider the common types of operations that the analytical tools allow us to do with our data.
3.1.1 Single Table Operations
Given a single data table, we may wish to do operations (illustrated in Figure 3.1) such as:
- Filtering: Extracting a subset of a dataset for analysis based on certain inclusion criteria for each record
- Aggregation: Grouping our data table by one or more variables and condensing information across records with aggregate functions like counts, sums, and averages
- Transformation: Create new columns or modifying existing columns to represent more complex or domain-specific context
3.1.2 Multiple Table Operations
Often, we can get additional value in an analysis by combining multiple types of information from difference tables. When working with multiple tables, we may be interested in:
- Combining Row-wise: Taking multiple tables with the same schemas (column names and data types) and creating a single table which contains the union (all records), intersection (only matching), or difference (only in one) of the records in the two tables
- Combining Column-wise: Appending additional fields to existing records through joining (also known as merging) multiple tables
3.1.3 Mechanics
All of these operations rely on a few core computational tasks:
- Arithmetic: Basic addition, subtraction, multiplication, and division to aggregate and transform data
- Equality: Comparing whether or not two values are equal is critical for data filtering, column-wise combination, and certain types of data transformation
- Casting: Converting data types of different elements into a comparable format is necessary for row-wise combination and often a prerequisite to certain equality and arithmetic tasks
While these operations may seem simple, their behavior within certain tools and when employed for certain data types may sometimes lead to unintuitive or misleading results.
3.2 Null Values
In Chapter 2 (Data Dalliances), we discuss how null values may represent many different concepts and be encoded in multiple different ways. In addition to those semantic challenges, various representations of null values may cause different computational problems.8 In this section, we will explore these potential failure modes.
3.2.1 Types of Null Values
Not only can null values represent many different things (as explored in Chapter 2), they also may be represented in many different ways. Understanding how nulls are encoded in one’s dataset is a critical prerequisite to attempting any of the computations described in the subsequent sections.
<IP_ADDRESS> Language representations
Different programming languages each offer their own versions of null values – and sometimes more than one. For example, the R language includes NA
, typed NA
s (e.g. NA_integer
, NA_character
), NaN
, and NULL
; meanwhile, core python has None
and the numpy
module provides a nan
.
These different values carry different semantic and functional meanings. For example R’s NA
generally means “the presence of an absence” whereas NULL
is “the absence of a presence.” This is articulated more clearly if we examine the lengths of these objects and observe that NA
has a length 1 whereas NULL
has a length 0.
## [1] 1 0
As further proof that these are not interchangeable, we may use the helper functions is.na()
and is.null()
. It’s false that NA
is NULL
and essentially unable to be evaluated if NULL
is NA
because NULL
s are truly nothing.9
## [1] TRUE TRUE FALSE
To further complicate matters, we have NaN
(“not a number”), along with -Inf
and Inf
, which generally arise when we attempt to abuse R’s calculator. Somewhat charmingly, Inf
and -Inf
may be used in some rudimentary calculations where the limit is returned.10
c(
1/0, # returns Inf
0/0, # returns NaN
1/Inf # returns 0
)
## [1] Inf NaN 0
<IP_ADDRESS> Data encoding choices (TODO)
Beyond these null types offered natively by different programming languages, there are also many different data management conventions for null values. Because null values can have many meanings, sometimes missing fields are encoded with “out of range” values which intend to suggest a type of missingness.
For example, the US Census Bureau’s Medical Expenditure Panel Survey uses the following reserved codes to denote different types of missingness: (TODO: cite p10 https://www.meps.ahrq.gov/data_stats/download_data/pufs/h206a/h206adoc.pdf)
- -1 INAPPLICABLE Question was not asked due to skip pattern
- -7 REFUSED Question was asked and respondent refused to answer question
- -8 DK Question was asked and respondent did not know answer
- -14 NOT YET TAKEN/USED Respondent answered that the medicine has not yet been used
- -15 CANNOT BE COMPUTED Value cannot be derived from data
This approach preserves a lot of relevant information while, at the same time, being readily apparent that these values are not valid when the data is manually inspect. Unfortunately, manually inspecting every data field is rarely possible, and such sentinel values may go undetected when looking at higher-level summaries.
Consider a survey of a population of retired adults where age is coded as 999
if not provided. Below, we simulate 100,000 such observations that are uniformly distributed between the age of 65 and 95 (hence, have an expected value of 80). Next, we replace merely half of a percent with our “null” values of 999
. Taking the mean with these false values results in a mean of about 85. This number alone might not raise the alarm; after all, we know the dataset’s population is older adults. However, accidentally treating these as valid values biases our results by a somewhat remarkable five years.
set.seed(123)
n <- 100000
p <- 0.005
ages <- runif(n, 65, 95)
ages_nulls <- ages
ages_nulls[1:(n*p)] <- 999
c(mean(ages), mean(ages_nulls))
## [1] 79.98 84.57
So, the first order of business with null values is understanding how they are encoded and translation them to the most computationally appropriate form. However, that is only the beginning of the story.
3.2.2 Aggregation
How null values are handled in the simple aggregation of data varies both across different languages and across different functions within a language. To better understand the problems this might cause, we will look at examples in R and SQL.
To explore aggregation, let’s build a simple dataset. We will suppose that we are working with a subscription-based e-commerce service and that we are looking at a monthly_spend
dataset with one record per customer and information about the amount they spent and returned in a given month:
spend <-
data.frame(
AMT_SPEND = c(10, 20, NA),
AMT_RETURN = rep(NA, 3)
)
To compute the average amount spent (AMT_SPEND
) with the dplyr
package, an analyst might first reasonably write the following summarize()
statement.
However, as we can see, due to the presence of null values within the AMT_SPEND
column, the result of this aggregation is for the whole quantity of AVG_SPEND
to be set to the value NA
.
A glance at the documentation for the mean()
function reveals that it has an na.rm
parameter which, when set to true, removes null values from our dataset.
Adding this argument to the previous statement allows us to reach a numerical answer.
## AVG_SPEND AVG_SPEND_NARM
## 1 NA 15
However, is this the right numerical answer?
What na.rm = TRUE
does is drop the null values from the set of numbers being averaged.
However, suppose the null values represent that no purchases were made.
That is, zero dollars were spent.
In effect, we have removed all non-purchasers from the data being averaged.
More precisely, we have switched from taking the average
\[ \frac{ \sum_{1}^{n} Spend }{\sum_{1}^{n} 1} \] over all \(n\) customers
to taking the average
\[ \frac{ \sum_{Spend > 0} Spend }{\sum_{Spend > 0} 1} \] over only those customers with spend
At face value, we could say that the code above is giving the incorrect answer; by dropping some low (zero) purchase amounts, the average amount spend per customer is inflated. A second perspective, which is someone more philosophically troubling, is that this tiny change to the code which fixed the obvious problem (returning a null value) has introduced a non-obvious problem by fundamentally changing the question that we are asking. By dropping all accounts from our table who made no purchases, we are no longer answering “What is the average amount spent by a new registrant?” but rather “What is the average amount spent by an actively engaged customer?” This technical quirk has significant analytical impact.
To answer the real question at hand, we would instead have a couple of options.
We could manually sum()
the amount spent with the option to drop nulls but then divide by the correct denominator (all observations – not just those with spend) or we could explicitly recode null values in AMT_SPEND
to zero before taking the average.11
Either of these options lead to the correct conclusion of a lower average spend amount.
summarize(
spend,
AVG_SPEND_MANUAL = sum(AMT_SPEND, na.rm = TRUE) / n(),
AVG_SPEND_RECODE = mean(coalesce(AMT_SPEND, 0))
)
## AVG_SPEND_MANUAL AVG_SPEND_RECODE
## 1 10 10
This is all well and good if we could just accept that the behaviors above are simply how nulls work, but further complexity comes as we see that there is no industry standard across tools.
For example, as the SQL code below shows, SQL’s avg()
function behaves more like R’s mean()
with the na.rm = TRUE
option set.
That is, the default behavior of SQL is to only operate on the valid and available values.
SELECT avg(amt_spend) as AVG_SPEND
FROM spend
## AVG_SPEND
## 1 15
However, this is not to suggest that null values cannot also be destructive in SQL.
While aggregation functions (which compute over the rows/records) like sum()
and avg()
drop nulls, operators like +
and -
(which compute across columns/variables in the same row/record) do not exhibit the same behavior.
Consider, for example, if we wish to calculate the average net purchase amount (purchases minus returns) instead of the gross (total) purchase amount.
SELECT avg(amt_spend-amt_return) as AVG_SPEND_NET
FROM spend
## AVG_SPEND_NET
## 1 NA
Despite what we learned above about SQL’s avg()
function, the query above returns only a null value.
What has happened?
In our spend
dataset, the amt_return
column is completely null (representing no returns).
Because the subtraction occurs before the average is taken, subtracting real numbers in amt_spend
with null values in amt_return
creates a column of all null values which are then fed into the avg()
function.
This process is shown step-by-step below.
SELECT
amt_spend,
amt_return, -amt_return
amt_spendFROM spend
## AMT_SPEND AMT_RETURN amt_spend-amt_return
## 1 10 NA NA
## 2 20 NA NA
## 3 NA NA NA
3.2.3 Comparison
Null values don’t just introduce complexity when doing arithmetic. Difficulties also arise any time multiple variables are assessed for equality or inequality. Since a null value is unknown, most programming languages generally will not consider nulls to be comparable with other nulls.
We can simple examples of this in both R and SQL.
c(
NA == 3,
NA > 10,
NA == NA
)
## [1] NA NA NA
SELECT
NULL = 3) as NULL_EQ_NUM,
(NULL > 10) as NULL_GT_NUM,
(NULL = NULL) as NULL_EQ_NULL (
## NULL_EQ_NUM NULL_GT_NUM NULL_EQ_NULL
## 1 NA NA NA
In these toy examples, such outcomes may seem perfectly logical. However, this same reasoning can arise in sneakier ways and lead to uninteded results when equality evaluations are implicit in the task at hand instead of the singular focus. We’ll now see examples from data filtering, joining, and transformation.
<IP_ADDRESS> Filtering
Suppose we want to split our dataset into two datasets based on high or low values of spend. We might assume the following two lines of code will create a clear partition12 of results.
However, examining the resulting datasets, we see than neither contains the null records.
spend_lt20
## AMT_SPEND AMT_RETURN
## 1 10 NA
spend_gte20
## AMT_SPEND AMT_RETURN
## 1 20 NA
The same situation results in SQL.
SELECT *
FROM spend
WHERE AMT_SPEND < 20
## AMT_SPEND AMT_RETURN
## 1 10 NA
SELECT *
FROM spend
WHERE AMT_SPEND >= 20
## AMT_SPEND AMT_RETURN
## 1 20 NA
Thus, whenever our data has null values, the very common act of data filtering risks excluding important information.
<IP_ADDRESS> Joining
The same phenomenon as described above also happens when joining multiple datasets.
Suppose we have multiple datasets we wish to merge based on columns denoting a record’s name and date of birthday. For ease of exploration, we will make the simplest possible such dataset and simply try to merge it to itself. (This may seem silly, but often when trying to understand computationally complex things, it is a good idea to make the scenario as simple as possible. In fact, this idea is core to the concept of computational unit tests which we will discuss at the end of this chapter.)
bday <- data.frame(NAME = c('Anne', 'Bob'), BIRTHDAY = c('2000-01-01', NA))
bday
## NAME BIRTHDAY
## 1 Anne 2000-01-01
## 2 Bob <NA>
In SQL, if we try to join this table, the records in row 1 will match because 'Anne' == 'Anne'
and '2000-01-01' == '2000-01-01'
.
However, poor Bob’s record is eliminated because his birthdate is logged as null, and NA == NA
is false.
SELECT a.*
FROM
as a
bday INNER JOIN
as b
bday ON
= b.NAME and
a.NAME = b.BIRTHDAY a.BIRTHDAY
## NAME BIRTHDAY
## 1 Anne 2000-01-01
In contrast, R’s dplyr::inner_join()
function will not do this by default.
This function lets us specifically control how nulls are matches with the na_matches
argument, with a default option to match on NA
values.
(You may read more about the argument by typing ?dplyr::inner_join
in the R console to pull up the documentation.)
inner_join(bday, bday, by = c('NAME', 'BIRTHDAY'))
## NAME BIRTHDAY
## 1 Anne 2000-01-01
## 2 Bob <NA>
This example then is not only a cautionary tale for how null values may unintentionally corrupt our data transformations but also how “brittle” our knowledge and intuition may be when moving between tools. Neither of these default behaviors is strictly better or worse, but they are definitely different and have real implications on our analysis.
<IP_ADDRESS> Transformation
A common task in data analysis is to aggregate results by subgroup. For example, we might want to summarize how many customers (rows/records) spent more or less than $10. To discern this, we might create a categorical variable for high versus low purchase amounts, group by this variable and count.
The psuedocode would read something like this:
%>%
data mutate(HIGH_LOW = << transform AMT_SPEND >>) %>%
group_by(HIGH_LOW) %>%
count()
To define the HIGH_LOW
variable, we might use a function like ifelse()
, dplyr::if_else()
, or dplyr::case_when()
.
However, once again, we have the issue of how values are partitioned when nulls are included.
If we recode any records with AMT_SPEND
of less than or equal to 10 to “Low” and default the rest to “High,” we will accidentally count all null values in the “High” group.
spend %>%
mutate(HIGH_LOW = case_when(
AMT_SPEND <= 10 ~ "Low",
TRUE ~ "High")
) %>%
group_by(HIGH_LOW) %>%
count()
## # A tibble: 2 x 2
## # Groups: HIGH_LOW [2]
## HIGH_LOW n
## <chr> <int>
## 1 High 2
## 2 Low 1
Instead, it is more accurate and transparent (unless we know specifically what null values mean and what group they should be part of) to not let one of our “core” categories by the “default” case in our logic. We can explicitly encode any residual values as something like “OTHER” or “ERROR” to help us see that there is a problem requiring extra attention.
spend %>%
mutate(HIGH_LOW = case_when(
AMT_SPEND <= 10 ~ "Low",
AMT_SPEND > 10 ~ "High",
TRUE ~ "OTHER")
) %>%
group_by(HIGH_LOW) %>%
count()
## # A tibble: 3 x 2
## # Groups: HIGH_LOW [3]
## HIGH_LOW n
## <chr> <int>
## 1 High 1
## 2 Low 1
## 3 OTHER 1
3.8 Trusting Tools
A theme throughout this book is the fundamentally social nature of data analysis. Data analysis is fraught without understanding the countless decisions made along the way by those who generated it (whose data is reflected), those who collected it, those who migrated it, and those who have posed questions of it. On one hand, this is a beautiful aspect of analysis; on the other hand, it means that analysts and their analyses are subject to all of the cognitive and social psychological biases of everyday humans.
One such bias is “social proof”: assuming that if a tool behaves a certain way, it must be because it is correct.
Assuming that our tools know best is admittedly an attractive proposition. It appeals to a desire to think that someone, somewhere is “in charge” and, perhaps more critically, helps us avoid a domino effect of distrust (If we don’t trust our tools how can we trust our results? And if we can’t trust our results, how can we trust anything at all?) Unfortunately, there are many reasons are tools might not know best. For example, the tool’s developer might have:
- Made a mistake
- Had a different analysis problem in mind with a different optimal approach
- Been optimizing for a different constraint (e.g. explainability vs. accuracy, speed vs. theoretical properties)
- Come from a community with different norms
- Been affording users the flexibility to do things many ways even if they don’t agree
- Built a certain feature for a different purpose than how you are using it
- Not thought about it at all
As a few concrete examples from popular open source tools. We’ll look briefly at the prominent python library scikitlearn
for machine learning and Apache Spark, an engine for large-scale distributed data processing.
3.8.1 Defaults in scikitlearn
scikitlearn
’s default behavior for logistic regression modeling13 automatically applies L2 regularization. You might or might not know what this means, and you might or might not want to apply it to your problem. That’s fine. The important thing is that it will change your estimates and predictions, and it is not a part of the classical definition of that algorithm (for modelers coming from a statistical background.)
Of course, there’s nothing inherently wrong about this choice; the library authors just had different goals than a typical statistical. scikitlearn
developer Olivier Grisel explains on Twitter that this choice (and others in the library) is explained because “Scikit-learn was always designed to make it easy to get good predictive accuracy (eg as measured by CV) rather than as statistical inference library.” Additionally, this choice is documented in bold in the function documentation.
However, an analyst could easily miss this nuance if they do not read the documentation. Or, if they misinterpret this choice as social proof that regularization is always the right approach, they might not make the best choice for their own analysis.
3.8.2 Algorithms in Spark
For example, according to a 2015 Jira ticket, developers of Spark considered multiple methodologies they could use when adding the functionality to compute feature importance for a random forest. Ultimately, a core contributor advised against permutation importance due to its computational cost.
Clearly, no one wants a workflow that is too costly or timely to run. So, once again, there is no right or wrong. However, since every approach to feature importance has its own biases, pitfalls, and challenges in interpretation, it’s a mistake for an end-user to not carefully understand which algorithm is used and why.


assigned
by Jane Sandberg at 2022-06-06 22:04:41.closed
by None at 2022-06-07 13:59:24.closed
by None at 2022-06-07 13:59:24.ready_for_review
by Jane Sandberg at 2022-06-06 22:06:46.referenced
by None at 2022-06-07 13:59:23.merged
by None at 2022-06-07 13:59:24.closed
by None at 2022-06-07 13:59:24.head_ref_deleted
by None at 2022-06-07 13:59:25.closed
by None at 2022-06-07 14:00:07.referenced
by None at 2022-06-07 14:00:07.merged
by None at 2022-06-07 14:00:07.closed
by None at 2022-06-07 14:00:07.head_ref_deleted
by None at 2022-06-07 14:00:08.assigned
by Jane Sandberg at 2022-06-07 17:01:50.I showed this to the stakeholder and got approval on the new look. Note: you will have to go to https://dss-staging.princeton.edu/catalog to see it
deployed
by None at 2022-06-07 17:54:56.ready_for_review
by Jane Sandberg at 2022-06-07 20:11:12.labeled
by Jane Sandberg at 2022-06-07 20:58:35.deployed
by None at 2022-06-07 17:45:11.ready_for_review
by Max Kadel at 2022-06-07 20:02:30.referenced
by Jane Sandberg at 2022-06-07 20:07:55.merged
by Jane Sandberg at 2022-06-07 20:07:55.closed
by Jane Sandberg at 2022-06-07 20:07:55.head_ref_deleted
by Jane Sandberg at 2022-06-07 20:07:56.labeled
by None at 2022-06-07 22:04:06.labeled
by None at 2022-06-07 22:04:11.Given the difficulties encountered in attempting to transfer the files between the QA server environment, the FTP server, and the S3 Bucket:
...an alternative proposed by @kelynch is to request to proceed with having the new staging
environment mirror that of the production
environment (hence, the same files and database exports could be used for both upgraded installations).
Waiting on signal sciences to verify before we delete the bucket
Digital Science confirmed we can use the production files that we have uploaded for this project both in prod and staging. They will send us an update on their progress setting up hosted environments on Friday this week.
I am removing "delete the bucket" from this ticket and will set a reminder/make a new ticket for the end of this project as part of cleanup.
mentioned
by Kate Lynch at 2022-06-07 13:41:26.subscribed
by Kate Lynch at 2022-06-07 13:41:26.closed
by Kate Lynch at 2022-06-07 14:49:18.labeled
by Kate Lynch at 2022-06-07 14:51:35.assigned
by James R. Griffin III at 2022-06-07 15:03:23.assigned
by Kate Lynch at 2022-06-07 15:03:27.unassigned
by James R. Griffin III at 2022-06-07 17:21:24.unassigned
by Kate Lynch at 2022-06-07 17:21:24.Resolved by the following:
labeled
by James R. Griffin III at 2022-06-07 17:23:18.labeled
by James R. Griffin III at 2022-06-07 17:23:23.These were submitted for import into Alma by DACS colleagues on 06/06/21 (yesterday) at 14:51 EDT.
labeled
by James R. Griffin III at 2022-06-07 17:23:35.labeled
by James R. Griffin III at 2022-06-07 17:23:40.The CI passes and this is a minor version. I am merging.
referenced
by None at 2022-06-07 14:44:16.merged
by None at 2022-06-07 14:44:16.closed
by None at 2022-06-07 14:44:16.head_ref_deleted
by None at 2022-06-07 14:44:17.labeled
by None at 2022-06-07 14:44:45.referenced
by Eliot Jordan at 2022-06-06 22:04:39.merged
by Eliot Jordan at 2022-06-06 22:04:39.closed
by Eliot Jordan at 2022-06-06 22:04:39.head_ref_deleted
by Eliot Jordan at 2022-06-06 22:04:39.closed by #5144
closed
by None at 2022-06-07 13:14:35.referenced
by None at 2022-06-07 13:13:47.merged
by None at 2022-06-07 13:13:47.closed
by None at 2022-06-07 13:13:47.head_ref_deleted
by None at 2022-06-07 13:13:48.Show page is working for most resources. Would be wise to check the show page for all resource types before closing this ticket.
Examples: https://aspace.princeton.edu/staff/resources/3757#tree::archival_object_1448310 (Content Warning Scope Note); https://aspace.princeton.edu/staff/resources/3950#tree::archival_object_1448342
Relates to https://github.com/pulibrary/pulfalight/issues/817
closed
by None at 2022-06-07 20:09:58.referenced
by None at 2022-06-07 20:09:58.merged
by None at 2022-06-07 20:09:58.closed
by None at 2022-06-07 20:09:59.head_ref_deleted
by None at 2022-06-07 20:09:59.@hackartisan @sdellis Page title generation no longer uses those methods. They can be removed.
For reference: 1. https://github.com/pulibrary/figgy/blob/rails-6-again/app/views/layouts/blacklight/base.html.erb#L11 2. https://github.com/projectblacklight/blacklight/blob/main/app/helpers/blacklight/blacklight_helper_behavior.rb#L30-L31 3. https://github.com/projectblacklight/blacklight/blob/main/app/views/catalog/_show_main_content.html.erb#L3
It looks like the coverage went down on this one. I imagine it's from adding back in the helper methods? I don't see any tests for those helper methods in the previous code. Is there any way to tell what code is not covered @hackartisan ?
@sdellis In the failed ci task click the "artifacts" tab and then click "coverage/html" and you'll see the coverage report https://output.circle-artifacts.com/output/job/559b38d1-ba66-4fe8-b3b0-263f92392897/artifacts/0/coverage/index.html#_AllFiles
mentioned
by Shaun Ellis at 2022-06-06 22:03:27.subscribed
by Shaun Ellis at 2022-06-06 22:03:27.mentioned
by None at 2022-06-07 14:00:46.subscribed
by None at 2022-06-07 14:00:46.mentioned
by Shaun Ellis at 2022-06-07 14:12:47.subscribed
by Shaun Ellis at 2022-06-07 14:12:47.referenced
by None at 2022-06-07 20:12:06.merged
by None at 2022-06-07 20:12:06.closed
by None at 2022-06-07 20:12:06.head_ref_deleted
by None at 2022-06-07 20:12:07.labeled
by None at 2022-06-07 21:16:09.labeled
by None at 2022-06-07 21:16:09.ready_for_review
by Eliot Jordan at 2022-06-07 21:12:56.head_ref_force_pushed
by Eliot Jordan at 2022-06-07 21:55:41.head_ref_force_pushed
by None at 2022-06-07 18:32:06.ready_for_review
by None at 2022-06-07 18:32:37.referenced
by Jane Sandberg at 2022-06-07 19:08:43.merged
by Jane Sandberg at 2022-06-07 19:08:43.closed
by Jane Sandberg at 2022-06-07 19:08:44.head_ref_deleted
by Jane Sandberg at 2022-06-07 19:08:44.assigned
by Jane Sandberg at 2022-06-07 20:33:02.head_ref_force_pushed
by Jane Sandberg at 2022-06-07 20:41:49.deployed
by None at 2022-06-07 20:43:10.referenced
by Jane Sandberg at 2022-06-07 20:44:48.merged
by Jane Sandberg at 2022-06-07 20:44:48.closed
by Jane Sandberg at 2022-06-07 20:44:48.head_ref_deleted
by Jane Sandberg at 2022-06-07 20:44:49.head_ref_force_pushed
by Jane Sandberg at 2022-06-07 20:13:29.deployed
by None at 2022-06-07 20:17:03.referenced
by None at 2022-06-07 21:00:14.deployed
by None at 2022-06-07 22:55:17.referenced
by Jane Sandberg at 2022-06-07 22:56:29.merged
by Jane Sandberg at 2022-06-07 22:56:29.closed
by Jane Sandberg at 2022-06-07 22:56:29.head_ref_deleted
by Jane Sandberg at 2022-06-07 22:56:30.deployed
by None at 2022-06-07 15:09:48.referenced
by None at 2022-06-07 16:12:11.merged
by None at 2022-06-07 16:12:11.closed
by None at 2022-06-07 16:12:11.head_ref_deleted
by None at 2022-06-07 16:12:12.@dependabot rebase
mentioned
by Dependabot at 2022-06-07 16:14:13.head_ref_force_pushed
by None at 2022-06-07 16:15:42.deployed
by None at 2022-06-07 16:18:16.deployed
by None at 2022-06-07 16:18:44.referenced
by None at 2022-06-07 16:20:38.merged
by None at 2022-06-07 16:20:38.closed
by None at 2022-06-07 16:20:38.head_ref_deleted
by None at 2022-06-07 16:20:39.referenced
by James R. Griffin III at 2022-06-07 16:26:56.merged
by James R. Griffin III at 2022-06-07 16:26:57.closed
by James R. Griffin III at 2022-06-07 16:26:57.head_ref_deleted
by James R. Griffin III at 2022-06-07 16:26:57.deployed
by None at 2022-06-07 21:49:38.referenced
by Jane Sandberg at 2022-06-07 21:53:58.merged
by Jane Sandberg at 2022-06-07 21:53:58.closed
by Jane Sandberg at 2022-06-07 21:53:59.head_ref_deleted
by Jane Sandberg at 2022-06-07 21:53:59.head_ref_force_pushed
by None at 2022-06-07 13:30:59.ready_for_review
by None at 2022-06-07 13:36:15.renamed
by None at 2022-06-07 13:36:44.head_ref_force_pushed
by None at 2022-06-07 13:42:00.assigned
by Bess Sadler at 2022-06-07 16:52:42.referenced
by Bess Sadler at 2022-06-07 16:53:15.merged
by Bess Sadler at 2022-06-07 16:53:15.closed
by Bess Sadler at 2022-06-07 16:53:16.head_ref_deleted
by Bess Sadler at 2022-06-07 16:53:16.labeled
by None at 2022-06-07 16:54:17.labeled
by None at 2022-06-07 16:54:17.referenced
by Bess Sadler at 2022-06-07 16:59:44.merged
by Bess Sadler at 2022-06-07 16:59:45.closed
by Bess Sadler at 2022-06-07 16:59:45.head_ref_deleted
by Bess Sadler at 2022-06-07 16:59:45.ready_for_review
by Francis Kayiwa at 2022-06-07 14:57:53.referenced
by Bess Sadler at 2022-06-07 15:11:47.merged
by Bess Sadler at 2022-06-07 15:11:47.closed
by Bess Sadler at 2022-06-07 15:11:47.head_ref_deleted
by Bess Sadler at 2022-06-07 15:11:48.head_ref_force_pushed
by Francis Kayiwa at 2022-06-07 15:47:19.referenced
by Bess Sadler at 2022-06-07 16:34:22.merged
by Bess Sadler at 2022-06-07 16:34:22.closed
by Bess Sadler at 2022-06-07 16:34:22.head_ref_deleted
by Bess Sadler at 2022-06-07 16:34:22.referenced
by Bess Sadler at 2022-06-07 16:35:10.merged
by Bess Sadler at 2022-06-07 16:35:10.closed
by Bess Sadler at 2022-06-07 16:35:10.head_ref_deleted
by Bess Sadler at 2022-06-07 16:35:11.Looked at this in the ansible meeting today - think we want to set maxsize
and daily
- the goal would be to rotate all logs once a day at a minimum, and to also rotate them any time a single log reaches a set size (possibly 500 MB?).
Related to #3060
Related to #3060
Closed by #3054.
closed
by Alicia Cozine at 2022-06-07 17:18:20.Mysqldbmigration is now working.
closed
by Alicia Cozine at 2022-06-07 17:19:29.head_ref_force_pushed
by Alicia Cozine at 2022-06-07 17:59:04.Can you say more about this?
deployed
by None at 2022-06-07 14:54:06.referenced
by None at 2022-06-07 14:56:04.merged
by None at 2022-06-07 14:56:04.closed
by None at 2022-06-07 14:56:05.head_ref_deleted
by None at 2022-06-07 14:56:05.The alerts happened in slack on #datadog-alerts on May 6th and 16th.


{% extends "index.html" %} {% block title %}RDFLib LOD Server{% endblock %} {% block intro %}
This is a Linked Open Data like server for rdflib. A SPARQL endpoint, conforming to the SPARQL Protocol with Joseki extensions is also included.
You can download this entire dataset as:


|
IMPACT Z
|
Modules | |
| module | transposeclass |
| This class defines a tranpose class which contains 2D and 3D tranpose functions. (Both arrays are distributed on 2D Cartisian processor array). | |
Functions/Subroutines | |
| subroutine | transposeclass::trans3d3_transp (nx, nsizey, nsizez, nsizexz, xin, xout, np, st |
| Subroutine Trans3d3: get the transpose of 3D double precision array with uneven distribution. More... | |
| subroutine | transposeclass::trans3d_transp (ny, nx, nysizex, nsizex, xin, tempmtr, np, stab |
| Subroutine Trans3d: get the transpose of 3D double precision array with uneven distribution. More... | |


◆ __init__()
| def onthefly_kratos_inlet_process.ImposeWindInletProcess.__init__ |
( |
|
self, |
|
|
|
Model, |
|
|
|
settings |
|
) |
| |
◆ ApplyRamp()
| def onthefly_kratos_inlet_process.ImposeWindInletProcess.ApplyRamp |
( |
|
self | ) |
|
◆ AssignVelocity()
| def onthefly_kratos_inlet_process.ImposeWindInletProcess.AssignVelocity |
( |
|
self | ) |
|
◆ Check()
| def onthefly_kratos_inlet_process.ImposeWindInletProcess.Check |
( |
|
self | ) |
|
◆ Create3DMappers()
| def onthefly_kratos_inlet_process.ImposeWindInletProcess.Create3DMappers |
( |
|
self, |
|
|
|
wind, |
|
|
|
old_blend_region = None |
|
) |
| |
◆ CreateMeanProfile()
| def onthefly_kratos_inlet_process.ImposeWindInletProcess.CreateMeanProfile |
( |
|
self, |
|
|
|
dim = 3 |
|
) |
| |
◆ ExecuteAfterOutputStep()
| def onthefly_kratos_inlet_process.ImposeWindInletProcess.ExecuteAfterOutputStep |
( |
|
self | ) |
|
◆ ExecuteBeforeOutputStep()
| def onthefly_kratos_inlet_process.ImposeWindInletProcess.ExecuteBeforeOutputStep |
( |
|
self | ) |
|
◆ ExecuteBeforeSolutionLoop()
| def onthefly_kratos_inlet_process.ImposeWindInletProcess.ExecuteBeforeSolutionLoop |
( |
|
self | ) |
|
◆ ExecuteFinalize()
| def onthefly_kratos_inlet_process.ImposeWindInletProcess.ExecuteFinalize |
( |
|
self | ) |
|
◆ ExecuteFinalizeSolutionStep()
| def onthefly_kratos_inlet_process.ImposeWindInletProcess.ExecuteFinalizeSolutionStep |
( |
|
self | ) |
|
◆ ExecuteInitialize()
| def onthefly_kratos_inlet_process.ImposeWindInletProcess.ExecuteInitialize |
( |
|
self | ) |
|
◆ ExecuteInitializeSolutionStep()
| def onthefly_kratos_inlet_process.ImposeWindInletProcess.ExecuteInitializeSolutionStep |
( |
|
self | ) |
|
◆ ExportToVTK()
| def onthefly_kratos_inlet_process.ImposeWindInletProcess.ExportToVTK |
( |
|
self | ) |
|
◆ inlet_nodes()
| def onthefly_kratos_inlet_process.ImposeWindInletProcess.inlet_nodes |
( |
|
self | ) |
|
◆ smoothstep()
| def onthefly_kratos_inlet_process.ImposeWindInletProcess.smoothstep |
( |
|
self, |
|
|
|
x, |
|
|
|
x_min = 0.0 , |
|
|
|
x_max = 1.0 , |
|
|
|
N = 3 |
|
) |
| |
◆ UpdateInletPosition()
| def onthefly_kratos_inlet_process.ImposeWindInletProcess.UpdateInletPosition |
( |
|
self | ) |
|
◆ block_num
| onthefly_kratos_inlet_process.ImposeWindInletProcess.block_num |
◆ bulk_wind_speed
| onthefly_kratos_inlet_process.ImposeWindInletProcess.bulk_wind_speed |
◆ friction_velocity
| onthefly_kratos_inlet_process.ImposeWindInletProcess.friction_velocity |
◆ inlet_position
| onthefly_kratos_inlet_process.ImposeWindInletProcess.inlet_position |
◆ mappers
| onthefly_kratos_inlet_process.ImposeWindInletProcess.mappers |
◆ mean_profile
| onthefly_kratos_inlet_process.ImposeWindInletProcess.mean_profile |
◆ model_part
| onthefly_kratos_inlet_process.ImposeWindInletProcess.model_part |
◆ wind
| onthefly_kratos_inlet_process.ImposeWindInletProcess.wind |
◆ wind_field
| onthefly_kratos_inlet_process.ImposeWindInletProcess.wind_field |
◆ x0
| onthefly_kratos_inlet_process.ImposeWindInletProcess.x0 |
The documentation for this class was generated from the following file:


[[template "header"]]
Rules - Three Names in a Hat
Rules
Setup
- Players are split between two teams
- Players take turns trying to get their team to guess the name they are given.
- Each round continues until there are no more names left.
- After 3 rounds the team with the most guessed names wins.
Rounds
- Give clues as long as it's not part of the person's name or a direct reference to their name.
For example they can't do things like "rhymes with" or "starts with X" or "ends with X".
- Same as previous rounds, except no words, only acting out silent clues.
- Same as round one except this time you only get one word.
[[template "footer"]]


Professor Gamer is British Academy Global Professor of English and Drama and Queen Mary University of London, and Professor of English and Comparative Literature at the University of Pennsylvania. He is author of Romanticism, Self-Canonization, and the Business of Poetry (Cambridge, 2017) and - as part of the Multigraph Collective - Interacting with Print: Modes of Reading in the Age of Print Saturation (Chicago, 2018). He is currently at work on a monograph, Romantic Melodrama: Feeling in Search of Form. In addition, he is (with Angela Wright) General Editor of The Cambridge Edition of the Works of Ann Radcliffe, and will edit The Italian for that series. Earlier work includes Romanticism and the Gothic (Cambridge, 2000), The Broadview Anthology of Romantic Drama (Broadview, 2003), and editions of Horace Walpole’s The Castle of Otranto (Penguin, 2002) and William Wordsworth and Samuel Coleridge’s Lyrical Ballads 1798 and 1800 (Broadview, 2008).
Deven Parker is a Postdoctoral Research Associate in the School of English and Drama at Queen Mary University of London, where she works on 18th- and 19th-century literature and theatre, media and technology studies, and the history of authorship. She received her PhD in 2019 from the University of Colorado, Boulder. Her work has been supported by the Huntington Library, McMaster University, and the Keats-Shelley Association of America, and has appeared in Studies in English Literature 1500-1900, the Keats-Shelley Journal, and Essays in Romanticism. She is currently at work on two book projects, the first on the rise of telecommunications networks in Romantic Britain and the second on the theatre’s influence on Romantic authorship.
Cassidy Holahan is a Ph.D. Candidate in the English Department of the University of Pennsylvania, specializing in British literature of the long eighteenth century. Her work focuses on the evolving relationship between novels and the theatre over the course of the century, and the authors who dabbled in both forms. She is currently a Mellon Mid-Doctoral Fellow for the 2020-2021 academic year at Penn’s Price Lab for Digital Humanities, where she is working on a digital database and networking project cataloguing adaptations of non-dramatic works to the eighteenth-century stage. Her work in digital humanities lies at the intersection of DH and book history, and past projects (found on her website) seek to elucidate how eighteenth-century readers read and interacted with physical books.


Custom plugins
Published 21 December 2017, 77 words, 1-minute read
The build.js
file defines how the site is built using Metalsmith and various plugins.
Several custom plugins have been created specifically for this site:
lib/metalsmith-debug.js
: output debugging information to the console.lib/metalsmith-setdate.js
: ensure each page has a date. If adate
is not defined in the page's front-matter, it is presumed to be the publish or file creation date.lib/metalsmith-moremeta.js
: applies further metadata to each page including the root folder, a default layout, primary and secondary navigation.