Replication of Study 1 of ‘Ecocentrism and Anthropocentrism: Moral Reasoning About Ecological Commons Dilemmas’ by Kortenkamp & Moore (2001, Journal of Environmental Psychology)

Author

Yash Patel (yashp@stanford.edu)

Published

December 15, 2025

Introduction

Facilitating pro-environmental behaviors can be, from a behavioral intervention approach, quite fickle. Interventions that work in the context of a survey may decay in their efficacy within the hour, or even the moment they step away from their computers. Accordingly, long-lasting interventions may have a reinforcement mechanism that the more touch-and-go interventions lack. We hypothesize that one such mechanism relates to forming and maintaining an environmentalist identity, via select subprocesses. One such subprocess may be how we conceptualize the environment morally. Kortenkamp & Moore (2001) found a relationship between pro-environmental attitudes and certain forms of moral reasoning. As it is quite dated, it would be good to check if the relationship still holds even decades from the original experiment.

Participants will be shown four ecological moral dilemmas (overgrazing, logging old-growth, logging protected redwood, and building a new landfill). The experiment will have a 2x2 design, where we will either 1) give or not give additional info on how the action will harm the environment, and 2) give or not give additional info on how the action will harm humans. Participants would be randomly assigned into one of these four groups, consistent for each dilemma. They will then be asked whether or not a character in the dilemma should perform or not support the damaging act. They will be asked to give four factors they took into consideration when making their decision.

These responses will then be coded and grouped into three categories: anthropocentric reasoning, ecocentric reasoning, and nonenvironmental reasoning. This may be the most difficult part of the methods, since the coding needs to be reliable and accurate.

  • Replication repository: https://github.com/psych251/kortenkamp2001
  • Original paper: https://www.sciencedirect.com/science/article/pii/S0272494401902051

Methods

Power Analysis

Original effect size, power analysis for samples to achieve 80%, 90%, 95% power to detect that effect size. Considerations of feasibility for selecting planned sample size.

Using WebPower, a 2x2 ANOVA design with 80% power and effect size of 0.25 will require N = 197, rounding to 50 per group.

Planned Sample

Planned sample size and/or termination rule, sampling frame, known demographics if any, preselection rules if any.

Due to both financial and time costs, the sample size will instead be 60 participants total. However, as each participant responds to four different dilemmas, the total number of moral consideration responses will be 240.

Materials

Grazing dilemma: “A common area of grazing land is shared by ten ranchers. All the ranchers know that the common grazing land is the perfect size for the total amount of cattle that they collectively own. If all the ranchers bought extra cattle they would overgraze the land, causing plant cover depletion, soil infertility and erosion, and the pollution of nearby waterways. Additionally, they would run each other out of business. The ranchers have an ‘unwritten’ commitment not to overuse the common grazing land. Though all the ranchers are business associates, they rarely socialize and are not really friends with each other. One of the ranchers, Steve, comes across a special deal where he can purchase a number of additional cattle for a very low price. Should Steve purchase additional cattle?”

Old growth dilemma: “Up until recently a large area of old growth forest has been set aside as parkland in a small town in British Columbia. Now the local lumber company, which owns the forest land, is planning a clear-cut harvest of the old growth trees. It has been a low period for the town and this new project means jobs and income for a number of years. Marie has lived in this town all her life. Most of Marie’s friends and previous co-workers are very excited about the new harvest and want to see the project happen. Both Marie and her husband were recently laid off by the company and will be rehired when this new harvest begins. However, she has learned that about 98% of old growth forests in North America have already been destroyed and that the unique old growth ecosystem is home to many rare species that cannot survive in other habitats. Additionally, she has learned that the jobs created by the harvest will only last until all the trees are cut, a few years, at which time Marie and her husband will again be laid off. Should Marie actively support or oppose the harvest?”

Garbage dilemma: “A regional area in the Midwest has a beautiful nature preserve that supports a diverse ecosystem of native plant and animal species, and is a very popular place for recreational activities. But this region also has a growing problem with what to do with the people’s garbage. The landfill site is almost at capacity. The local governmental department of waste management has developed two proposals to deal with the situation. The first is to build a second landfill site. The best location for the new site is the nature preserve. If the landfill is sited here it would completely destroy the preserve’s ecosystem. Additionally, if the landfill is sited here it would decrease property values of the many neighboring residences. However, the land already belongs to the district and no new fees would be required under this proposal. The second proposal would involve creating a new collection system that would force all people to separate their garbage into seven categories six for recycling and one for composting. Substantial fines would be charged to anyone who doesn’t abide by the new regulations. Additionally, the residents of the greater regional area would be charged with a monthly fee in order to pay for the added costs necessary to run this waste collection system. Sarah and Kurt, residents of the area, will participate in a public vote on this issue next week. Should Sarah and Kurt vote for building the new landfill or vote to establish the new collection system?”

Gathering dilemma: “In a rural area, a government forest preserve has been set up as part of a project to restore the mountain forests. The forests are rapidly disappearing because so much wood is needed by the village people for cooking and heating. On the mountain slopes that have been deforested, the soil is being washed away by the heavy rains which makes it very difficult for young tree seedlings to grow into mature trees. As a result the deficient forest is unable to support a diverse and healthy animal population. Additionally, the deficient forest is unable to support the firewood needs of the community. Past the forest preserve there is a designated firewood gathering area. The local women all have the daily job of walking up the steep mountain slopes toward the designated area to cut firewood for use in cooking and heating. This task grows harder over time because the women have to go farther and farther before they can obtain enough wood for their families’ needs. One of the women, Sandy, hikes past the nearby forest preserve and thinks to herself, ‘‘My task would be so much easier if I could only cut those trees.’’ She would then be able to bring back some extra wood to sell. However, she knows that it is against the law to take trees from the preserve, and that anyone who is caught doing so will be severely punished. But she also knows the forest ranger has gone to the city for a few days. She wonders, ‘‘Perhaps today I will cut just one tree.’’ Should Sandy cut a tree from the government forest?”

EAS: I try hard to carry my proenvironmental beliefs over into all the other parts of my life. I try to appear pro-environmental to please others, but I really don’t believe environmental issues are important. Because of my personal values, I believe that ignoring environmental matters is OK. I try to act pro-environmentally because of pressure from others. Although today’s PC (Politically Correct) standards pressure me to express pro-environmental views, I don’t really believe the environment is threatened. When it comes to questions about the environment, I feel driven to know the truth. If I did something that might harm the environment, I would be concerned that others would be angry with me. I do not attempt to appear proenvironmental to others. According to my personal values, ignoring human impacts on the larger ecosystem is OK. It is not important for me to appear pro-environmental to others. I am motivated by my personal beliefs to try to protect the environment. The interrelatedness of all living things in the ecosystem is something I have never felt personally compelled to consider. I try to express only my proenvironmental views in order to avoid negative reactions from others. What happens to the larger ecosystem, beyond what happens to humans, doesn’t make much difference to me. I have not found it essential to try to protect the larger ecosystem, beyond what happens to humans. Because of today’s PC (Politically Correct) standards, I try to appear pro-environment. It is personally important to me to try to protect the larger ecosystem, beyond what happens to humans.

Procedure

Original paper:

“Small groups of participants (n=2 to 8) met for one session with an experimenter and answered the packet of materials individually in writing. For each moral dilemma they were asked to decide whether the main character should or should not support or perform an environmentally damaging action. They were then asked to list and explain four factors they had considered most important in making their decision. All individuals listed at least one consideration, and seven was the maximum number listed for any one dilemma. They answered the EAS following the dilemmas.

The moral considerations given by the participants were coded into three categories: ecocentric, anthropocentric, and nonenvironmental. The criteria were similar to those of Kahn (1997). For example, a response was categorized as ecocentric if it referred to the rights or intrinsic value of nature or proposed protecting nature for nature’s sake. A response was coded as anthropocentric if it proposed preserving nature to benefit humans or because humans cannot survive without nature, and the nonenvironmental category was used when a response referred to social contracts, guilt, or truthfulness. An example of an ecocentric consideration is, ‘Plants and animals that live there would have to ¢nd a new habitat’. An example of an anthropocentric consideration is, ‘Additional cattle will deplete the land of its resources, and make it unusable for many years to come.’ An example of a nonenvironmental consideration is, ‘Steve should honor the ‘unwritten’ commitment. Trust is very important. . .’ Twenty per cent of the questionnaires were coded by a second rater for reliability (per cent agreement = 85 6). Disagreements were resolved by using the decisions of the primary coder.”

Deviations:

Instead of small groups, each participants completed the survey individually and online (as opposed to on a packet). Additionally, there was no second rater for this replication project.ChatGPT was used to see if it was able to code similar results, however all analysis used just the human-coded data.

Analysis Plan

Can also quote directly, though it is less often spelled out effectively for an analysis strategy section. The key is to report an analysis strategy that is as close to the original - data cleaning rules, data exclusion rules, covariates, etc. - as possible.

As each participant has to generate a response for each dilemma, no explicit attention check will be included. Instead, empty or nonsensical responses will be removed.

A generalized linear regression with interactions between the environmental- and anthropocentric-enhanced information and the moral considerations will be run, with the frequency of those moral considerations as the DV.

A linear regression with the dilemma used as the IV and ecocentric moral consideration as the DV will be run.

A multinomial log-linear model with the Environmental Attitude Scale as the IV and the moral consideration given as the DV will be run.

Clarify key analysis of interest here You can also pre-specify additional analyses you plan to do.

Differences from Original Study

Instead of college students, I will sample from a representative US population. Instead of having them complete the survey on packets, they will do them as an online Qualtrics survey. Some additional demographic variables will also be collected, such as gender, age, and geographic area (urban, suburban, or rural).

Explicitly describe known differences in sample, setting, procedure, and analysis plan from original study. The goal, of course, is to minimize those differences, but differences will inevitably occur. Also, note whether such differences are anticipated to make a difference based on claims in the original article or subsequent published research on the conditions for obtaining the effect.

Methods Addendum (Post Data Collection)

Actual Sample

Sample size, demographics, data exclusions based on rules spelled out in analysis plan

No participants were excluded, as all given responses were relevant to the dilemmas, resulting in a final sample of N = 60 (median age = 47.5, %female = 51.7%, %urban = 25%, %suburban = 58.3%, %rural = 16.7%)

Differences from pre-data collection methods plan

Any differences from what was described as the original plan, or “none”.

none

Results

Data preparation

Data preparation following the analysis plan.

Confirmatory analysis

The analyses as specified in the analysis plan.

Side-by-side graph with original graph is ideal here

df |> 
    mutate(
        anthro_impact = ifelse(condition %in% c("anthro", "both"), "Present", "Absent"),
        anthro_impact = factor(anthro_impact, levels = c("Present", "Absent")),
        env_impact = fct_relevel(env_impact, "Absent"),
        anthro_impact = fct_relevel(anthro_impact, "Absent"),
        resp_coded = factor(resp_coded)
    ) |> 
    count(env_impact, anthro_impact, resp_coded) |> 
    glm(
        n ~ env_impact * anthro_impact * resp_coded,
        family = poisson,
        data = _
    ) |> 
    summary()

Call:
glm(formula = n ~ env_impact * anthro_impact * resp_coded, family = poisson, 
    data = count(mutate(df, anthro_impact = ifelse(condition %in% 
        c("anthro", "both"), "Present", "Absent"), anthro_impact = factor(anthro_impact, 
        levels = c("Present", "Absent")), env_impact = fct_relevel(env_impact, 
        "Absent"), anthro_impact = fct_relevel(anthro_impact, 
        "Absent"), resp_coded = factor(resp_coded)), env_impact, 
        anthro_impact, resp_coded))

Coefficients:
                                                         Estimate Std. Error
(Intercept)                                              1.791759   0.408248
env_impactPresent                                        1.427116   0.454606
anthro_impactPresent                                     0.154151   0.556349
resp_codedanthro                                         1.504077   0.451335
resp_codednon                                            1.152680   0.468293
env_impactPresent:anthro_impactPresent                  -0.539813   0.639021
env_impactPresent:resp_codedanthro                      -1.778514   0.544367
env_impactPresent:resp_codednon                         -1.598967   0.567273
anthro_impactPresent:resp_codedanthro                    0.105361   0.612480
anthro_impactPresent:resp_codednon                      -0.007547   0.638443
env_impactPresent:anthro_impactPresent:resp_codedanthro  0.380385   0.757764
env_impactPresent:anthro_impactPresent:resp_codednon     0.878718   0.779356
                                                        z value Pr(>|z|)    
(Intercept)                                               4.389 1.14e-05 ***
env_impactPresent                                         3.139 0.001694 ** 
anthro_impactPresent                                      0.277 0.781722    
resp_codedanthro                                          3.333 0.000861 ***
resp_codednon                                             2.461 0.013838 *  
env_impactPresent:anthro_impactPresent                   -0.845 0.398250    
env_impactPresent:resp_codedanthro                       -3.267 0.001086 ** 
env_impactPresent:resp_codednon                          -2.819 0.004822 ** 
anthro_impactPresent:resp_codedanthro                     0.172 0.863420    
anthro_impactPresent:resp_codednon                       -0.012 0.990568    
env_impactPresent:anthro_impactPresent:resp_codedanthro   0.502 0.615679    
env_impactPresent:anthro_impactPresent:resp_codednon      1.127 0.259534    
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

(Dispersion parameter for poisson family taken to be 1)

    Null deviance: 4.0712e+01  on 11  degrees of freedom
Residual deviance: 4.4409e-16  on  0  degrees of freedom
AIC: 80.879

Number of Fisher Scoring iterations: 3

Looking at the effect of including the environmental impact information on the moral considerations used.

df |> 
    group_by(resp_coded, env_impact) |> 
    mutate(n = n()) |> 
    ggplot(aes(x = resp_coded, y = n, fill = env_impact)) +
    geom_col(position = position_dodge(preserve = "single")) +
    ylab("N consideration used") +
    xlab("Moral consideration categories") +
    scale_x_discrete(labels= c("Eco", "Anthro", "Non-env")) +
    scale_fill_grey(name = "Env. impacts") +
    theme_bw() +
    theme(aspect.ratio = 1)

Figure 1 from original paper

Looking at the distribution of ecocentric moral reasoning for each dilemma

df |> 
    mutate(
        anthro_impact = ifelse(condition %in% c("anthro", "both"), "Present", "Absent"),
        anthro_impact = factor(anthro_impact, levels = c("Present", "Absent")),
        env_impact = fct_relevel(env_impact, "Absent"),
        anthro_impact = fct_relevel(anthro_impact, "Absent"),
        resp_coded = factor(resp_coded),
        dilemma = factor(dilemma),
        env_reason = as.numeric(resp_coded == "eco")
    ) |> 
    lm(
        env_reason ~ dilemma,
        data = _
    ) |> 
    summary()

Call:
lm(formula = env_reason ~ dilemma, data = mutate(df, anthro_impact = ifelse(condition %in% 
    c("anthro", "both"), "Present", "Absent"), anthro_impact = factor(anthro_impact, 
    levels = c("Present", "Absent")), env_impact = fct_relevel(env_impact, 
    "Absent"), anthro_impact = fct_relevel(anthro_impact, "Absent"), 
    resp_coded = factor(resp_coded), dilemma = factor(dilemma), 
    env_reason = as.numeric(resp_coded == "eco")))

Residuals:
     Min       1Q   Median       3Q      Max 
-0.46667 -0.28333 -0.15000 -0.01667  0.98333 

Coefficients:
                  Estimate Std. Error t value Pr(>|t|)    
(Intercept)        0.01667    0.05025   0.332  0.74041    
dilemmafirewood    0.13333    0.07106   1.876  0.06184 .  
dilemmaold_growth  0.26667    0.07106   3.753  0.00022 ***
dilemmagarbage     0.45000    0.07106   6.333  1.2e-09 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 0.3892 on 236 degrees of freedom
Multiple R-squared:  0.1568,    Adjusted R-squared:  0.146 
F-statistic: 14.62 on 3 and 236 DF,  p-value: 9.106e-09
df |> 
    group_by(dilemma) |> 
    summarize(n = mean(resp_coded == "eco")) |> 
    ggplot(aes(x = dilemma, y = n)) +
    geom_col() +
    ylab("Mean Eco-centric considerations used") +
    xlab("Dilemma topic") +
    scale_x_discrete(labels= c("Grazing", "Gathering", "Old growth", "Garbage")) +
    theme_bw() +
    theme(aspect.ratio = 1)

Figure 2 from original paper Effect of EAS on moral considerations

df |> 
    multinom(resp_coded ~ eas, data = _) |>
    summary()
# weights:  9 (4 variable)
initial  value 263.666949 
final  value 255.636104 
converged
Call:
multinom(formula = resp_coded ~ eas, data = df)

Coefficients:
       (Intercept)        eas
anthro    1.860678 -0.1934632
non       1.070238 -0.1016654

Std. Errors:
       (Intercept)       eas
anthro    1.049102 0.1600929
non       1.108216 0.1685492

Residual Deviance: 511.2722 
AIC: 519.2722 
# Alternative analysis

df |> 
    mutate(resp_coded = factor(resp_coded, levels = c("non", "eco", "anthro"))) |> 
    lm(eas ~ resp_coded, data = _) |> 
    summary()

Call:
lm(formula = eas ~ resp_coded, data = mutate(df, resp_coded = factor(resp_coded, 
    levels = c("non", "eco", "anthro"))))

Residuals:
    Min      1Q  Median      3Q     Max 
-4.6225 -0.5174  0.2621  0.6954  1.6288 

Coefficients:
                 Estimate Std. Error t value Pr(>|t|)    
(Intercept)        6.4225     0.1226  52.391   <2e-16 ***
resp_codedeco      0.1108     0.1942   0.571    0.569    
resp_codedanthro  -0.1179     0.1651  -0.714    0.476    
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 1.117 on 237 degrees of freedom
Multiple R-squared:  0.006544,  Adjusted R-squared:  -0.001839 
F-statistic: 0.7806 on 2 and 237 DF,  p-value: 0.4593
df |> 
    group_by(resp_coded) |> 
    summarise(mean_eas = mean(eas)) |> 
    ggplot(aes(x = resp_coded, y = mean_eas)) +
    geom_col(position = position_dodge(preserve = "single")) +
    ylab("Environmental Attitudes Scale") +
    xlab("Moral consideration categories") +
    scale_x_discrete(labels= c("Eco", "Anthro", "Non-env")) +
    theme_bw() +
    theme(aspect.ratio = 1)

Exploratory analyses

tbl <- df %>%
  count(geography, resp_coded) %>%
  tidyr::pivot_wider(
    names_from = resp_coded,
    values_from = n,
    values_fill = 0
  )

chisq.test(as.matrix(tbl[,-1]))

    Pearson's Chi-squared test

data:  as.matrix(tbl[, -1])
X-squared = 0.47909, df = 4, p-value = 0.9755
df |> 
    group_by(geography) |> 
    summarize(n = mean(resp_coded == "eco")) |> 
    ggplot(aes(x = geography, y = n)) +
    geom_col() +
    ylab("Mean Eco-centric considerations used") +
    xlab("Urbanicity") +
    theme_bw() +
    theme(aspect.ratio = 1)

ChatGPT coding

library(httr2)
Warning: package 'httr2' was built under R version 4.4.3
library(jsonlite)

Attaching package: 'jsonlite'
The following object is masked from 'package:purrr':

    flatten
library(dplyr)
library(purrr)
library(tibble)
library(glue)
SYSTEM_PROMPT <- "You are a careful qualitative coder. Return ONLY valid JSON. No markdown."

TASK_PROMPT <- "
Code each text into one of:
- eco: if it referred to the rights or intrinsic value of nature or proposed protecting nature for nature’s sake
- anthro: proposed preserving nature to benefit humans or because humans cannot survive without nature
- non: referred to social contracts, guilt, or truthfulness

You must code them into only one of those categories. If you are uncertain, categorize it into the one you are most confident of.
"

call_openai_code_batch <- function(df_chunk, model = "gpt-4.1-mini") {
  items <- df_chunk %>% transmute(ResponseId, text = resp)

  req <- request("https://api.openai.com/v1/chat/completions") |>
    req_auth_bearer_token(Sys.getenv("OPENAI_API_KEY")) |>
    req_body_json(list(
      model = model,
      temperature = 0,
      messages = list(
        list(role = "system", content = SYSTEM_PROMPT),
        list(role = "user", content = paste0(
          TASK_PROMPT,
          "\n\nInput JSON array (ResponseId, text):\n",
          toJSON(items, auto_unbox = TRUE)
        )),
        list(
          role = "user",
          content = paste(
            "Return ONLY a JSON array of objects with fields:",
            "ResponseId (same as input) and code (one of eco, anthro, non).",
            "No extra keys, no commentary."
          )
        )
      )
    )) |>
    req_retry(max_tries = 5, backoff = ~ 2^(.x))

  resp <- req_perform(req)
  out_text <- resp_body_json(resp)$choices[[1]]$message$content

  coded <- as_tibble(fromJSON(out_text))

  # Safety check: force code to allowed set (will error if model misbehaves)
  allowed <- c("eco", "anthro", "non")
  if (!all(coded$code %in% allowed)) {
    bad <- unique(coded$code[!(coded$code %in% allowed)])
    stop("Model returned invalid code(s): ", paste(bad, collapse = ", "), call. = FALSE)
  }

  coded
}

code_tibble <- function(df, batch_size = 50, model = "gpt-4.1-mini") {
  df %>%
    mutate(.row = row_number(), batch = ceiling(.row / batch_size)) %>%
    group_by(batch) %>%
    group_split() %>%
    map_dfr(~ call_openai_code_batch(.x, model = model)) %>%
    right_join(df, by = "ResponseId")
}
# coded_df <- code_tibble(df, batch_size = 50)
# write_csv(coded_df, "../data/data_gpt-anon.csv")
coded_df <- read_csv("../data/data_gpt-anon.csv")
Rows: 960 Columns: 13
── Column specification ────────────────────────────────────────────────────────
Delimiter: ","
chr (11): ResponseId, code, condition, variable, value, resp, gender, geogra...
dbl  (2): eas, age

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
chisq.test(table(coded_df$code, coded_df$resp_coded))

    Pearson's Chi-squared test

data:  table(coded_df$code, coded_df$resp_coded)
X-squared = 52.056, df = 4, p-value = 1.343e-10

Discussion

Summary of Replication Attempt

Open the discussion section with a paragraph summarizing the primary result from the confirmatory analysis and the assessment of whether it replicated, partially replicated, or failed to replicate the original result.

While not all of the analyses replicated, the primary findings did. For example, the original authors found that adding information about the environmental impacts of a certain action would increase the number of anthropocentric moral considerations given, which they found surprising. This was not found in the replication, and the expected result of anthropocentric reasoning decreasing when given ecocentric information was found. More importantly, when given information about environmental impacts, ecocentric moral reasoning increased, which was the primary finding. Additionally, the finding that the “grazing fields” dilemma had the least amount of ecocentric moral reasoning was also replicated, which is expected since the grazing dilemma is a tragedy of the commons scenario where social factors are much more salient. The finding of EAS not having an influence on moral considerations provided was also replicated.

Commentary

Despite the relatively lengthy time since the original study was conducted, their findings were generally replicated, suggesting that the moral considerations of Americans regarding certain environmental dilemmas remains fairly stable. More over, the more diverse sample demographics gives evidence to the argument that their findings are generalizable.

The exploratory analysis found that urbanicity had no influence on ecocentric moral considerations, suggesting that people’s environmental moral reasoning is relatively consistent regardless of geography. This consistency would suggest that interventions that appeal to environmental ethics should be similarly effective regardless of location.

Surprisingly, using ChatGPT to code the responses resulted in similar coding compared to manual coding, which was not my experience using ChatGPT in previous projects. This does suggest, however, that LLMs are able to parse moral reasoning statements and extract the primary considerations used, allowing for automation in these coding pipelines. A followup question would be whether or not LLMs can extract moral considerations from a broader set of domains as opposed to the four rather limited scenarios in this current study.