Mikroökonomie
Vorlesung 1

Prof. Frank Pisch PhD

Motivation

Nachfrage als eine Seite auf allen Märkten

manager magazin

tagesschau.de

Aggregierte Nachfrage

destatis

Um Märkte zu verstehen, brauchen wir eine Vorstellung der Nachfrage

  • Zusammen mit dem Angebot bestimmt sie Preise und Konsum

  • Sie sagt uns, wer wie viel konsumiert und somit wie es um die Konsumentenwohlfahrt steht

Individuelle Nachfrage

Marktnachfrage wird (heutzutage) immer auf individuelle Nachfragen, also auf das Entscheidungsverhalten von einzelnen Konsument zurückgeführt.

In der Einführungsvorlesung haben wir uns Ihre Nachfrage nach Smartphones angesehen. Wovon hängt sie ab?

  • Ihr Bedarf bzw. Ihre Wünsche

  • Ihr (knappes) Budget und der Preis

  • Ob Sie beides gut in Einklang bringen können

In der VWL haben wir dafür spezielle Namen, aber die Interpretation ist gleich

  • Präferenzen

  • Budget

  • Ob Sie rational und insbesondere nutzenmaximierend handeln

Überblick und Ressourcen

Ziele

  • Verstehen, wie Ökonomen über Präferenzen und Budgets nachdenken

  • Analysieren, wie optimale Nachfrageentscheidungen und eine Marktnachfrage zustande kommen

  • Nützliche Konzepte entwickeln und verstehen, die uns auch später helfen werden

    • Inbesondere in Bezug auf Wohlfahrt

Ressourcen

  • (Einige) Kapitel im Varian: 2 - 8, 14, 15

  • Interaktive Diagramme

Budget

Der Zweigüterfall

Betrachten wir 2 Güter – ohne Beschränkung der Allgemeinheit

  • Waren, Dienstleistungen, andere Dinge wie frische Luft

Ein Güterbündel ist \(\boldsymbol{x} \equiv (x_1,x_2)\), wobei \(x_i\geq 0\) die konsumierte  Menge darstellt

Die dazugehörigen Preise \(p_i\) pro Einheit sind für Konsumenten gegeben und einheitlich

Das verfügbare Budget ist \(m\)

Budgetbeschränkung: Was kann man sich leisten?

Die Budgetmenge enthält alle Güterbündel, die bei den aktuellen Preisen erschwinglich sind \[ \boldsymbol{x}'\boldsymbol{p} = p_1 x_1 + p_2 x_2 \leq m \]

Sie wird durch die Budgetgerade abgegrenzt, also die Menge aller Güterbündel, die das Budget vollkommen erschöpfen

\[ x_2 = \frac{m}{p_2}-\frac{p_1}{p_2}x_1 \]

Die Steigung zeigt an, mit welcher Rate die beiden Güter auf der Budgetgerade füreinander substituiert werden können, also die Opportunitätskosten

Opportunitätskosten

Opportunitätskosten sind allgemein die ökonomischen Kosten einer Entscheidung, also der Wert der nächstbesten ungenutzten Alternative. Im Kontext der Budgetgeraden entsprechen diese der Steigung:

\[ \frac{\mathrm{d}x_2}{\mathrm{d}x_1} = -\frac{p_1}{p_2} \]

Opportunitätskosten im Fokus

Opportunitätskosten sind vielleicht das wichtigste Konzept in den Wirtschaftswissenschaften (und darüber hinaus)

Einige Beispiele:

  • Studieren und insbesondere ein Doktorat haben hohe Opportunitätskosten: entgangenes Einkommen und Erfahrung

  • Jede Ausgabe – zum Beispiel eine Investition – hat Opportunitätskosten in Höhe des “Zinses”, den das Geld angelegt erwirtschaftet hätte

  • DIY (z.B. Heimwerkeln) ist immer eine Abwägung, da die eigene Zeit auch anders genutzt werden kann

    • Putzhilfe in der WG??
  • Forschung vs Administration und Spezialisierung nach komparativem Vorteil

Aber kehren wir zurück zur Budgetbeschränkung…

Budgetbeschränkung: was kann man sich leisten?

#| standalone: true
#| viewerHeight: 600

library(shiny)
options(shiny.mathjax.url = "https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.7/MathJax.js")
library(ggplot2)

# Define UI
ui <- fluidPage(
  br(),
  withMathJax(),
  sidebarLayout(
    sidebarPanel(
      h3("Nutzenmaximierung"),
      tabsetPanel(
        tabPanel("Hauptmenü", width = "400px",
                 br(),
                 p("\\(\\alpha\\) ist der Hauptparameter für die Nutzenfunktion. Unter \"Erweitert\" finden Sie weitere Optionen und können Budgetbeschränkungen umschalten."),
                 sliderInput(inputId = "alpha",
                             label = "Wähle \\(\\alpha\\)", 
                             min = 0.01,
                             max = 0.99,
                             value = 0.5,
                             step = 0.01),
                 selectInput("utilityType",
                             "Wähle Nutzenfunktion:",
                             choices = c("Cobb-Douglas" = "cd", 
                                         "Perfekte Substitute" = "ps",
                                         "Perfekte Komplemente" = "pc"
                                         
                                         # ,
                                         # "CES" = "ces"
                                         
                                         )),
                             
                 uiOutput('formula'),
                 
                 checkboxInput("showBudgetLine",
                               "Zeige Budgetbeschränkung",
                               value = FALSE),
                 checkboxInput("showIndifferenceCurve",
                               "Zeige Indifferenzkurven",
                               value = FALSE)
                 
        ),
        tabPanel("Erweitert",
                 br(),
                 sliderInput("Px",
                             "Preis von Gut 1",
                             min = 1,
                             max = 5,
                             value = 4,
                             step = 0.1),
                 sliderInput("Py",
                             "Preis von Gut 2",
                             min = 1,
                             max = 5,
                             value = 2,
                             step = 0.1),
                 sliderInput("budget",
                             "Budget",
                             min = 100,
                             max = 300,
                             value = 200,
                             step = 1),
                 br(),
                 
                 actionButton("reset", "Reset")
                 
        )
      )
    ),
    mainPanel(
      align="center",
      plotOutput(outputId = "utilityPlot", height = "550px", width = "600px"),
    )
  )
)

# Define server logic
server <- function(input, output) {
  
  # Define utility functions
  utility_function <- function(alpha, x, y, type) {
    if (type == "cd") {
      return(x^alpha * y^(1 - alpha))
    }
    if (type == "ps") {
      return(alpha*x + (1-alpha)*y)
    }
    if (type == "pc") {
      return(pmin(alpha*x, y))
    }
    
    # if (type == "ces") {
    #   rho = 0.5 
    #   return((alpha*x^rho + (1-alpha)*y^rho)^(1/rho))
    # }
    
  }
  
  # Find maximal utility
  maximizeUtility <- function(budget, Px, Py, alpha, type) {
    if (type == "cd") {
      quantity_x <- (alpha * budget) / Px
      quantity_y <- ((1 - alpha) * budget) / Py
      max_utility <- utility_function(alpha, quantity_x, quantity_y, "cd")
    } else if (type == "ps") {
      utility_per_dollar_x <- alpha / Px
      utility_per_dollar_y <- (1 - alpha) / Py
      if (utility_per_dollar_x > utility_per_dollar_y) {
        quantity_x <- budget / Px
        quantity_y <- 0
      } else {
        quantity_x <- 0
        quantity_y <- budget / Py
      }
      max_utility <- utility_function(alpha, quantity_x, quantity_y, "ps")
    } else if (type == "pc") {
      quantity_x <- budget / (Px + alpha * Py)
      quantity_y <- alpha * (budget / (Px + alpha * Py))
      max_utility <- utility_function(alpha, quantity_x, quantity_y, "pc")
    } 
    
    # else if (type == "ces") {
    #   objective_function <- function(x) {
    #     y <- (budget - Px*x) / Py
    #     utility_function(alpha, x, y, "ces")
    #   }
    #   lower_bound <- 0
    #   upper_bound <- budget / Px
    #   optimization_result <- optimize(objective_function, interval = c(lower_bound, upper_bound), maximum = TRUE)
    #   quantity_x <- optimization_result$maximum
    #   quantity_y <- (budget - Px*quantity_x) / Py
    #   max_utility <- optimization_result$objective
    # } 
    
    else {
      stop("Unknown utility function type.")
    }
    return(list(max_utility = max_utility, quantity_x = quantity_x, quantity_y = quantity_y))
  }
  
  output$utilityPlot <- renderPlot({
    alpha <- input$alpha
    Px <- input$Px
    Py <- input$Py
    budget <- input$budget
    type <- input$utilityType
    showBudgetLine <- input$showBudgetLine
    showIndifferenceCurve <- input$showIndifferenceCurve
    
    maxutil_all <- maximizeUtility(budget, Px, Py, alpha, type)
    maxutil <- maxutil_all$max_utility
    quantity_x <- maxutil_all$quantity_x
    quantity_y <- maxutil_all$quantity_y
    
    x <- c(seq(1, 100, by = 2), seq(round(quantity_x*0.75, 1), round(quantity_x*1.25, 1), by = .1))
    y <- c(seq(1, 100, by = 2), seq(round(quantity_y*0.75, 1), round(quantity_y*1.25, 1), by = .1))
    grid <- expand.grid(x = x, y = y)
    grid$utility <- utility_function(alpha, grid$x, grid$y, type)
    
    if(showIndifferenceCurve) {
    plot <- ggplot(grid, aes(x = x, y = y)) +
      geom_contour(aes(z = utility), breaks = c(maxutil), color = "red") +
      geom_contour(aes(z = utility), breaks = c(maxutil*0.8, maxutil*1.2), color = "red", linetype = "dashed") +
      coord_cartesian(xlim = c(0, 100), ylim = c(0, 100)) +
      theme_minimal()+
      labs(x = expression(x[1]), y = expression(x[2])) +
      theme(
        axis.title.x = element_text(size = 20),  # Adjust the font size of x-axis label
        axis.title.y = element_text(size = 20)   # Adjust the font size of y-axis label
      )
    
    } else if(showBudgetLine){
      plot <- ggplot(grid, aes(x = x, y = y)) + 
        geom_abline(intercept = budget/Py, slope = -Px/Py, color = "blue") +
        geom_blank() +
        coord_cartesian(xlim = c(0, 100), ylim = c(0, 100)) +
        theme_minimal()+
        labs(x = expression(x[1]), y = expression(x[2])) +
        theme(
          axis.title.x = element_text(size = 20),  # Adjust the font size of x-axis label
          axis.title.y = element_text(size = 20)   # Adjust the font size of y-axis label
        )
      
    } else {
      plot <- ggplot(grid, aes(x = x, y = y)) +
        coord_cartesian(xlim = c(0, 100), ylim = c(0, 100)) +
        theme_minimal()+
        labs(x = expression(x[1]), y = expression(x[2])) + 
        theme(
          axis.title.x = element_text(size = 20),  # Adjust the font size of x-axis label
          axis.title.y = element_text(size = 20)   # Adjust the font size of y-axis label
        )
      }
    
    
    
    if(showBudgetLine && showIndifferenceCurve){
      plot <- plot + geom_abline(intercept = budget/Py, slope = -Px/Py, color = "blue")+
        annotate("segment", x = quantity_x, xend = quantity_x, y = 0, yend = quantity_y, linetype = "dashed")+
        annotate("segment", x = 0, xend = quantity_x, y = quantity_y, yend = quantity_y, linetype = "dashed")+
        annotate("label", x = quantity_x, y = 0, label = round(quantity_x, 2))+
        annotate("label", x = 0, y = quantity_y, label = round(quantity_y, 2))+
        geom_contour(aes(z = utility), breaks = c(maxutil), color = "red") +
        geom_contour(aes(z = utility), breaks = c(maxutil*0.8, maxutil*1.2), color = "red", linetype = "dashed") +
        coord_cartesian(xlim = c(0, 100), ylim = c(0, 100)) +
        theme_minimal()+
        labs(x = expression(x[1]), y = expression(x[2])) +
        theme(
          axis.title.x = element_text(size = 20),  # Adjust the font size of x-axis label
          axis.title.y = element_text(size = 20)   # Adjust the font size of y-axis label
        )
    }
    plot
  })
  
  observeEvent(input$reset, {
    
    updateSliderInput(inputId = "alpha", value = 0.5)
    updateCheckboxInput(inputId = "showBudgetLine", value = FALSE)
    updateCheckboxInput(inputId = "showIndifferenceCurve", value = FALSE)
    updateSliderInput(inputId = "Px", value = 4)
    updateSliderInput(inputId = "Py", value = 2)
    updateSliderInput(inputId = "budget", value = 200)
    
  })
  
  
  
  
  
  output$formula <- renderUI({
    formula <- switch(input$utilityType,
                      "cd" = "$$U(x_1, x_2) = x_1^{\\alpha} x_2^{1-\\alpha}$$",
                      "ps" = "$$U(x_1, x_2) = \\alpha x_1 + (1-\\alpha) x_2$$",
                      "pc" = "$$U(x_1, x_2) = \\min(\\alpha x_1, x_2)$$",
                      
                      
                      #"ces" = "$$U(x, y) = (\\alpha x^{\\rho} + (1-\\alpha) y^{\\rho})^{\\frac{1}{\\rho}}$$",
                
                      "")
    withMathJax("Formel: ", formula)
  })
}

# Run the application
shinyApp(ui = ui, server = server)

Präferenzen und Nutzen

Präferenzen: was möchte man haben?

In der VWL modellieren wir Bedürfnisse und Wünsche mithilfe von Präferenzen

  • Nehmen wir zwei Güterbündel, \(\boldsymbol{x} = (x_1,x_2)\) und \(\boldsymbol{y} = (y_1,y_2)\)
    • Sagen wir, Gut 1 ist ein iPhone 15, Gut 2 ein Samsung S24
  • Manche von Ihnen bevorzugen strikt Apple; dann schreiben wir \[ (1,0) \succ (0,1) \]
  • Und wenn ich Ihnen noch ein S24 oben drauf packe? Dann sind Sie vielleicht indifferent \[ (1,0) \sim (0,2) \]
  • Vielleicht ist es Ihnen nicht ganz klar, aber Sie finden das S24 ganz sicher nicht besser? Dann haben Sie eine schwache Präferenz für das iPhone \[ (1,0) \succsim (0,1) \]

Alle Operatoren zeigen Präferenzrelationen – diese werden uns sehr helfen, wenn wir die Nachfrage finden wollen

“Vernünftige” Präferenzen

Wir nehmen für unsere Konsumenten zumeist an, dass ihre Präferenzen bestimmte Eigenschaften erfüllen, sodass sie “wohlverhalten” sind (man also mit ihnen gut arbeiten kann):

  1. vollständig \[ \boldsymbol{x} \succsim \boldsymbol{y} \ \ \lor \ \ \boldsymbol{y} \succsim \boldsymbol{x} \ \ \ \ \forall \ \boldsymbol{x}, \boldsymbol{y} \]

  2. reflexiv \[ \boldsymbol{x} \succsim \boldsymbol{x} \ \ \ \ \forall \ \boldsymbol{x} \]

  3. transitiv (das \(\land\) steht für das logische “Und”) \[ \boldsymbol{x} \succsim \boldsymbol{y} \ \ \land \ \ \boldsymbol{y} \succsim \boldsymbol{z} \ \ \implies \ \boldsymbol{x} \succsim \boldsymbol{z} \ \ \ \ \forall \ \boldsymbol{x}, \boldsymbol{y}, \boldsymbol{z} \]

  4. monoton \(\leftrightarrow\) keine Sättigung \[ x_i \geq y_i \ \ \ \ \forall \ i \ \ \implies \ \ \boldsymbol{x} \succsim \boldsymbol{y} \]

  5. stetig

Teamarbeit: wie realitätsfern sind diese Annahmen?

Nützliche Beschreibung: Die Nutzenfunktion

Optimale Entscheidungen nur mithilfe von Präferenzrelationen zu finden ist schwierig…

Können wir vielleicht jedem Bündel einen Wert zuweisen, sodass die Präferenzen repräsentiert werden?

  • Mit unseren Annahmen ist dies garantiert!

  • Wir haben dann sogar wohlverhaltene Funktionen

Diese  Nutzenfunktionen werden zumeist als \(u(\boldsymbol{x}) = u(x_1,x_2)\) notiert



Teamarbeit: Gehen Sie zurück auf Folie 13 und finden Sie Funktionen, die die jeweiligen Präferenzen repräsentieren könnten!

Kardinaler vs Ordinaler Nutzen

Sie haben sicher festgestellt: die gleichen Präferenzen können durch unendlich viele Funktionen dargestellt werden

Nutzenfunktionen sind also immer ordinal: Sie geben nur Reihenfolgen an und absolute (kardindale) Unterschiede im Nutzenwert haben keine Bedeutung

Somit können wir immer monotone Transformationen auf Nutzenfunktionen anwenden und die resultierende Funktion repräsentiert die selben Präferenzen!

Das steht in großen Kontrast zur Volkswirtschaftslehre in den Anfängen: im 18. Jahrhundert war “Nutzen” messbar und absolut…

Beispiele für Nutzenfunktionen

  • Perfekte Substitute

\[ u(\boldsymbol{x}) = x_1 + x_2 \]

  • Perfekte Komplemente

\[ u(\boldsymbol{x}) = \mathrm{min}\{x_1,x_2\} \]

  • Cobb-Douglas

\[ u(\boldsymbol{x}) = x_1^{\alpha}x_2^{1-\alpha} \ \ \ \ \text{with} \ \alpha \in (0,1) \]

  • Quasilineare Präferenzen

\[ u(\boldsymbol{x}) = v(x_1) + x_2, \ \ \ \ \ \text{mit} \ \ \ \ v'>0, \ \ v''<0 \]

Teamarbeit: Beschreiben Sie das Verhalten dieser Präferenzen in Worten!

Nützliche Konzepte und das Verhalten von Nutzenfunktionen

Überblick

In diesem Teil lernen wir zwei nützliche Konzepte kennen, die uns helfen werden, Nutzenfunktionen besser zu verstehen und später die Nachfrage herzuleiten.

  • Grenznutzen

  • Indifferenzkurven

Auch wenn beide Konzepte zunächst formalistisch anmuten, können wir sie mithilfe von Beispielen leicht verstehen.

Oktoberfest

DALL-E

Grenznutzen ist positiv, aber abnehmend!

DALL-E

Indifferenzkurven geben an, in welchen Verhältnissen Güter konsumiert werden können, ohne dass sich das Nutzenniveau ändert.

Zentrales Konzept: Grenznutzen

Betrachten wir den Fall eines einzigen Gutes, sodass der Nutzen \(u=u(x)\) ist

Wie finden wir das beste Güterbündel ohne Budgetrestriktion?

  • Starten wir bei eine beliebigen Konsummenge \(x=k\). Wollen wir mehr oder weniger konsumieren?

  • Wenn der zusätzliche Nutzen der nächsten Einheit größer als der Preis (gemessen in Nutzen) ist, wollen wir mehr! Wenn er niedriger ist, wollen wir den Konsum reduzieren.

Grenznutzen

Der Grenznutzen eines Gutes \(i\) (Marginal Utility), \[ \frac{\partial u(\boldsymbol{x})}{\partial x_i} \equiv MU_i(\boldsymbol{x}), \] ist der marginale Zusatznutzen, wenn man die Menge um eine infinitesimale Einheit erhöht.

Hinweise:

  • Typischerweise fällt der Grenznutzen eines Gutes, wenn man mehr konsumiert

  • Mit mehreren Gütern ist es komplizierter, aber der Grenznutzen wird dennoch eine zentrale Rolle spielen

Zentrales Konzept: Indifferenzkurven

Um das beste Güterbündel – und auch die Nachfrage – zu finden, werden wir ein sehr nützliches Konzept nutzen: Indifferenzkurven

  • Sie sind Mengenscharen aller Güterbündel, die den gleichen Nutzenwert erzeugen; also solche, zwischen denen ein:e Konsument:in indifferent ist

\[ \{\boldsymbol{x}|u(\boldsymbol{x})=\bar{u}\} \]

  • Ihre Form zeigt uns, wie gerne wir substitutieren, also freiwillig von einem Gut weniger und von anderen mehr konsumieren würden

Indifferenzkurven im Zweigüterfall

#| standalone: true
#| viewerHeight: 600

library(shiny)
options(shiny.mathjax.url = "https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.7/MathJax.js")
library(ggplot2)

# Define UI
ui <- fluidPage(
  br(),
  withMathJax(),
  sidebarLayout(
    sidebarPanel(
      h3("Nutzenmaximierung"),
      tabsetPanel(
        tabPanel("Hauptmenü", width = "400px",
                 br(),
                 p("\\(\\alpha\\) ist der Hauptparameter für die Nutzenfunktion. Unter \"Erweitert\" finden Sie weitere Optionen und können Budgetbeschränkungen umschalten."),
                 sliderInput(inputId = "alpha",
                             label = "Wähle \\(\\alpha\\)", 
                             min = 0.01,
                             max = 0.99,
                             value = 0.5,
                             step = 0.01),
                 selectInput("utilityType",
                             "Wähle Nutzenfunktion:",
                             choices = c("Cobb-Douglas" = "cd", 
                                         "Perfekte Substitute" = "ps",
                                         "Perfekte Komplemente" = "pc"
                                         
                                         # ,
                                         # "CES" = "ces"
                                         
                                         )),
                             
                 uiOutput('formula'),
                 
                 checkboxInput("showBudgetLine",
                               "Zeige Budgetbeschränkung",
                               value = FALSE),
                 checkboxInput("showIndifferenceCurve",
                               "Zeige Indifferenzkurven",
                               value = FALSE)
                 
        ),
        tabPanel("Erweitert",
                 br(),
                 sliderInput("Px",
                             "Preis von Gut 1",
                             min = 1,
                             max = 5,
                             value = 4,
                             step = 0.1),
                 sliderInput("Py",
                             "Preis von Gut 2",
                             min = 1,
                             max = 5,
                             value = 2,
                             step = 0.1),
                 sliderInput("budget",
                             "Budget",
                             min = 100,
                             max = 300,
                             value = 200,
                             step = 1),
                 br(),
                 
                 actionButton("reset", "Reset")
                 
        )
      )
    ),
    mainPanel(
      align="center",
      plotOutput(outputId = "utilityPlot", height = "550px", width = "600px"),
    )
  )
)

# Define server logic
server <- function(input, output) {
  
  # Define utility functions
  utility_function <- function(alpha, x, y, type) {
    if (type == "cd") {
      return(x^alpha * y^(1 - alpha))
    }
    if (type == "ps") {
      return(alpha*x + (1-alpha)*y)
    }
    if (type == "pc") {
      return(pmin(alpha*x, y))
    }
    
    # if (type == "ces") {
    #   rho = 0.5 
    #   return((alpha*x^rho + (1-alpha)*y^rho)^(1/rho))
    # }
    
  }
  
  # Find maximal utility
  maximizeUtility <- function(budget, Px, Py, alpha, type) {
    if (type == "cd") {
      quantity_x <- (alpha * budget) / Px
      quantity_y <- ((1 - alpha) * budget) / Py
      max_utility <- utility_function(alpha, quantity_x, quantity_y, "cd")
    } else if (type == "ps") {
      utility_per_dollar_x <- alpha / Px
      utility_per_dollar_y <- (1 - alpha) / Py
      if (utility_per_dollar_x > utility_per_dollar_y) {
        quantity_x <- budget / Px
        quantity_y <- 0
      } else {
        quantity_x <- 0
        quantity_y <- budget / Py
      }
      max_utility <- utility_function(alpha, quantity_x, quantity_y, "ps")
    } else if (type == "pc") {
      quantity_x <- budget / (Px + alpha * Py)
      quantity_y <- alpha * (budget / (Px + alpha * Py))
      max_utility <- utility_function(alpha, quantity_x, quantity_y, "pc")
    } 
    
    # else if (type == "ces") {
    #   objective_function <- function(x) {
    #     y <- (budget - Px*x) / Py
    #     utility_function(alpha, x, y, "ces")
    #   }
    #   lower_bound <- 0
    #   upper_bound <- budget / Px
    #   optimization_result <- optimize(objective_function, interval = c(lower_bound, upper_bound), maximum = TRUE)
    #   quantity_x <- optimization_result$maximum
    #   quantity_y <- (budget - Px*quantity_x) / Py
    #   max_utility <- optimization_result$objective
    # } 
    
    else {
      stop("Unknown utility function type.")
    }
    return(list(max_utility = max_utility, quantity_x = quantity_x, quantity_y = quantity_y))
  }
  
  output$utilityPlot <- renderPlot({
    alpha <- input$alpha
    Px <- input$Px
    Py <- input$Py
    budget <- input$budget
    type <- input$utilityType
    showBudgetLine <- input$showBudgetLine
    showIndifferenceCurve <- input$showIndifferenceCurve
    
    maxutil_all <- maximizeUtility(budget, Px, Py, alpha, type)
    maxutil <- maxutil_all$max_utility
    quantity_x <- maxutil_all$quantity_x
    quantity_y <- maxutil_all$quantity_y
    
    x <- c(seq(1, 100, by = 2), seq(round(quantity_x*0.75, 1), round(quantity_x*1.25, 1), by = .1))
    y <- c(seq(1, 100, by = 2), seq(round(quantity_y*0.75, 1), round(quantity_y*1.25, 1), by = .1))
    grid <- expand.grid(x = x, y = y)
    grid$utility <- utility_function(alpha, grid$x, grid$y, type)
    
    if(showIndifferenceCurve) {
    plot <- ggplot(grid, aes(x = x, y = y)) +
      geom_contour(aes(z = utility), breaks = c(maxutil), color = "red") +
      geom_contour(aes(z = utility), breaks = c(maxutil*0.8, maxutil*1.2), color = "red", linetype = "dashed") +
      coord_cartesian(xlim = c(0, 100), ylim = c(0, 100)) +
      theme_minimal()+
      labs(x = expression(x[1]), y = expression(x[2])) +
      theme(
        axis.title.x = element_text(size = 20),  # Adjust the font size of x-axis label
        axis.title.y = element_text(size = 20)   # Adjust the font size of y-axis label
      )
    
    } else if(showBudgetLine){
      plot <- ggplot(grid, aes(x = x, y = y)) + 
        geom_abline(intercept = budget/Py, slope = -Px/Py, color = "blue") +
        geom_blank() +
        coord_cartesian(xlim = c(0, 100), ylim = c(0, 100)) +
        theme_minimal()+
        labs(x = expression(x[1]), y = expression(x[2])) +
        theme(
          axis.title.x = element_text(size = 20),  # Adjust the font size of x-axis label
          axis.title.y = element_text(size = 20)   # Adjust the font size of y-axis label
        )
      
    } else {
      plot <- ggplot(grid, aes(x = x, y = y)) +
        coord_cartesian(xlim = c(0, 100), ylim = c(0, 100)) +
        theme_minimal()+
        labs(x = expression(x[1]), y = expression(x[2])) + 
        theme(
          axis.title.x = element_text(size = 20),  # Adjust the font size of x-axis label
          axis.title.y = element_text(size = 20)   # Adjust the font size of y-axis label
        )
      }
    
    
    
    if(showBudgetLine && showIndifferenceCurve){
      plot <- plot + geom_abline(intercept = budget/Py, slope = -Px/Py, color = "blue")+
        annotate("segment", x = quantity_x, xend = quantity_x, y = 0, yend = quantity_y, linetype = "dashed")+
        annotate("segment", x = 0, xend = quantity_x, y = quantity_y, yend = quantity_y, linetype = "dashed")+
        annotate("label", x = quantity_x, y = 0, label = round(quantity_x, 2))+
        annotate("label", x = 0, y = quantity_y, label = round(quantity_y, 2))+
        geom_contour(aes(z = utility), breaks = c(maxutil), color = "red") +
        geom_contour(aes(z = utility), breaks = c(maxutil*0.8, maxutil*1.2), color = "red", linetype = "dashed") +
        coord_cartesian(xlim = c(0, 100), ylim = c(0, 100)) +
        theme_minimal()+
        labs(x = expression(x[1]), y = expression(x[2])) +
        theme(
          axis.title.x = element_text(size = 20),  # Adjust the font size of x-axis label
          axis.title.y = element_text(size = 20)   # Adjust the font size of y-axis label
        )
    }
    plot
  })
  
  observeEvent(input$reset, {
    
    updateSliderInput(inputId = "alpha", value = 0.5)
    updateCheckboxInput(inputId = "showBudgetLine", value = FALSE)
    updateCheckboxInput(inputId = "showIndifferenceCurve", value = FALSE)
    updateSliderInput(inputId = "Px", value = 4)
    updateSliderInput(inputId = "Py", value = 2)
    updateSliderInput(inputId = "budget", value = 200)
    
  })
  
  
  
  
  
  output$formula <- renderUI({
    formula <- switch(input$utilityType,
                      "cd" = "$$U(x_1, x_2) = x_1^{\\alpha} x_2^{1-\\alpha}$$",
                      "ps" = "$$U(x_1, x_2) = \\alpha x_1 + (1-\\alpha) x_2$$",
                      "pc" = "$$U(x_1, x_2) = \\min(\\alpha x_1, x_2)$$",
                      
                      
                      #"ces" = "$$U(x, y) = (\\alpha x^{\\rho} + (1-\\alpha) y^{\\rho})^{\\frac{1}{\\rho}}$$",
                
                      "")
    withMathJax("Formel: ", formula)
  })
}

# Run the application
shinyApp(ui = ui, server = server)

Steigung der Indifferenzkurve: die Grenzrate der Substitution

Um das beste Güterbündel – also die Nachfrage – zu finden, wollen wir die höchste Indifferenzkurve finden, auf der mind. ein Güterbündel in der Budgetmenge liegt

  • Es wird also ein Tangenzialpunkt gesucht: Im Optimum ist die Steigung der Indifferenzkurve genauso groß wie die Steigung der Budgetgeraden!

Die Steigung der Indifferenzkurve wird als  Grenzrate der Substitution bezeichnet (Marginal Rate of Substitution)

  • Für ein beliebiges Nutzenniveau \(k\) und eine Nutzenfunktion für zwei Güter \(u(x_1,x_2)\):

\[ \mathrm{d} u(x_1,x_2) = \mathrm{d} k = 0 = \frac{\partial u}{\partial x_1} \mathrm{d} x_1 + \frac{\partial u}{\partial x_2} \mathrm{d} x_2 \Leftrightarrow \]

\[ \frac{\mathrm{d} x_2}{\mathrm{d} x_1} = \underbrace{- \frac{\frac{\partial u}{\partial x_1}}{\frac{\partial u}{\partial x_2}}}_{\text{Grenzrate der Substitution}} \equiv - \frac{MU_1}{MU_2} \equiv MRS_{1,2} \]

Eigenschaften der MRS

Die MRS ist bei differenzierbaren Nutzenfunktionen negativ

  • Wenn man von einem Gut mehr konsumiert, kann man ohne Nutzenverlust weniger von einem anderen konsumieren

Sie gibt den “Wechselkurs” an, zu der Konsument:innen bereit sind, Güter füreinander auszutauschen

Bei schwach konvexen Präferenzen fällt die MRS nicht; bei strikt konvexen Präferenzen steigt sie

  • D.h. \(|MRS|\) nimmt typischerweise schwach ab

  • Man muss also immer mehr von einem Gut aufgeben, um den Nutzen durch Konsum des anderen Gutes konstant zu halten

Individuelle Nachfrage

Überblick

In diesem Teil leiten wir uns die individuelle Nachfrage als Funktion des Budgets und der Güterpreise her

  • Zunächst mithilfe des Lagrange Ansatzes (also ein bisschen Analysis)

  • Anschließend bilden wir Intuition mithilfe der grafischen Lösung im Zweigüterfall

Im nächsten Schritt können wir dann über Konsument:innen aggregieren, um die Marktnachfrage zu erhalten

Der Lagrange Ansatz

  • Das Problem ist, Güterbündel zu wählen, die den Nutzen unter Einhaltung der Budgetbedingung zu maximieren:

\[ \mathrm{max}_{\boldsymbol{x}} \ \ u(\boldsymbol{x}) \ \ \ \ \ \text{u.d.N.} \ \ \ \ \boldsymbol{x}'\boldsymbol{p} \leq m \]

  • Wir verwenden die Lagrange-Methode mit Multiplikator \(\lambda\): \[ \mathrm{max}_{\boldsymbol{x},\lambda} \ \ \ \mathscr{L} = u(\boldsymbol{x}) + \lambda (m-\boldsymbol{x}'\boldsymbol{p}) \]
  • Die notwendigen Bedingungen erster Ordnung geben uns ein Gleichungssystem, das wir für \(\boldsymbol{x}^*, \ \lambda^*\) lösen können

\[ \left. \frac{\partial u(.)}{\partial x_i} \right |_{\boldsymbol{x^*}} = MU_i|_{\boldsymbol{x^*}} = \lambda^* p_i \ \ \ \ \ \ \ \forall i \]

\[ m = \boldsymbol{x^*} \ ' \boldsymbol{p} \]

  • Beachte: Im Zuge dieser Veranstaltung kennzeichnen wir alle optimalen Lösungen mit einem Asterisk \(*\)

Optimale Nachfrage

Dividieren wir die Bedingungen erster Ordnung für zwei Güter \(i\) und \(j\) durcheinander und multiplizieren mit \(-1\), erhalten wir einen richtig nützlichen Ausdruck: \[ \underbrace{ \left. -\frac{\frac{\partial u(.)}{\partial x_i}}{\frac{\partial u(.)}{\partial x_j}} \right |_{\boldsymbol{x^*}} = \left. - \frac{MU_i}{MU_j} \right |_{\boldsymbol{x^*}}}_{\text{Grenzrate der Substitution}} = \underbrace{-\frac{p_i}{p_j}}_{\text{Steigung der Budgetgeraden}} \]

Wie schon antizipiert, erfüllt das optimale Güterbündel die oben erwähnte Tangenzialbedingung von Indifferenzkurve und Budgetgerade

Weitere Intuition:

  • Nehmen wir an, dass für ein Güterbündel \(MRS(x_1',x_2')>p_1/p_2\): der relative Grenznutzen von Gut 1 ist somit hoch im Vergleich zum relativen Preis. Somit möchte man mehr von Gut 1 und weniger von Gut 2 konsumieren

  • Bei diesem sub-optimalen Güterbündel würde man also gerne auf das relativ teure Gut 2 verzichten und mehr vom relativ billigen Gut 1 konsumieren

  • Für Fortgeschrittene: \(\lambda\) ist der Grenznutzen des Einkommens bzw. sein Schattenpreis

Verifizieren Sie das bitte in der grafischen Analyse weiter unten.

Beispiel: Cobb-Douglas

Mit einer expliziten Nutzenfunktion können wir nun die individuelle Nachfrage ausrechnen:

  • Nehmen wir Cobb-Douglas Präferenzen an, also

\[ u(x_1,x_2)=x_1^{\alpha}x_2^{1-\alpha} \ \ \ \ \ \text{mit} \ \alpha \in (0,1) \]

  • Die beiden übrig gebliebenen Gleichungen sind also

\[ -\frac{\alpha}{1-\alpha} \frac{x_2^*}{x_1^*} = - \frac{p_1}{p_2} \ \ \ \Leftrightarrow \ \ \ x_2^* = \frac{1-\alpha}{\alpha} \frac{p_1}{p_2}x_1^* \] \[ m=x_1^*p_1 + x_2^*p_2 \]

  • Sodass

\[ x_1^* \equiv x_1(p_1,p_2,m) = \frac{\alpha \ m}{p_1}, \ \ \ x_2^*\equiv x_2(p_1,p_2,m) = \frac{(1-\alpha) \ m}{p_2} \]

  • Mit Cobb-Douglas Präferenzen gibt man also einen konstanten Teil \(\alpha\) für Gut 1 und den Rest für Gut 2 aus
  • Nota bene: wir gehen ein paar Abkürzungen, aber Sie wissen sicher, wie Sie die Lagrange-Methode vollständig korrekt anwenden ;)

Grafische Lösung

#| standalone: true
#| viewerHeight: 600

library(shiny)
options(shiny.mathjax.url = "https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.7/MathJax.js")
library(ggplot2)

# Define UI
ui <- fluidPage(
  br(),
  withMathJax(),
  sidebarLayout(
    sidebarPanel(
      h3("Nutzenmaximierung"),
      tabsetPanel(
        tabPanel("Hauptmenü", width = "400px",
                 br(),
                 p("\\(\\alpha\\) ist der Hauptparameter für die Nutzenfunktion. Unter \"Erweitert\" finden Sie weitere Optionen und können Budgetbeschränkungen umschalten."),
                 sliderInput(inputId = "alpha",
                             label = "Wähle \\(\\alpha\\)", 
                             min = 0.01,
                             max = 0.99,
                             value = 0.5,
                             step = 0.01),
                 selectInput("utilityType",
                             "Wähle Nutzenfunktion:",
                             choices = c("Cobb-Douglas" = "cd", 
                                         "Perfekte Substitute" = "ps",
                                         "Perfekte Komplemente" = "pc"
                                         
                                         # ,
                                         # "CES" = "ces"
                                         
                                         )),
                             
                 uiOutput('formula'),
                 
                 checkboxInput("showBudgetLine",
                               "Zeige Budgetbeschränkung",
                               value = FALSE),
                 checkboxInput("showIndifferenceCurve",
                               "Zeige Indifferenzkurven",
                               value = FALSE)
                 
        ),
        tabPanel("Erweitert",
                 br(),
                 sliderInput("Px",
                             "Preis von Gut 1",
                             min = 1,
                             max = 5,
                             value = 4,
                             step = 0.1),
                 sliderInput("Py",
                             "Preis von Gut 2",
                             min = 1,
                             max = 5,
                             value = 2,
                             step = 0.1),
                 sliderInput("budget",
                             "Budget",
                             min = 100,
                             max = 300,
                             value = 200,
                             step = 1),
                 br(),
                 
                 actionButton("reset", "Reset")
                 
        )
      )
    ),
    mainPanel(
      align="center",
      plotOutput(outputId = "utilityPlot", height = "550px", width = "600px"),
    )
  )
)

# Define server logic
server <- function(input, output) {
  
  # Define utility functions
  utility_function <- function(alpha, x, y, type) {
    if (type == "cd") {
      return(x^alpha * y^(1 - alpha))
    }
    if (type == "ps") {
      return(alpha*x + (1-alpha)*y)
    }
    if (type == "pc") {
      return(pmin(alpha*x, y))
    }
    
    # if (type == "ces") {
    #   rho = 0.5 
    #   return((alpha*x^rho + (1-alpha)*y^rho)^(1/rho))
    # }
    
  }
  
  # Find maximal utility
  maximizeUtility <- function(budget, Px, Py, alpha, type) {
    if (type == "cd") {
      quantity_x <- (alpha * budget) / Px
      quantity_y <- ((1 - alpha) * budget) / Py
      max_utility <- utility_function(alpha, quantity_x, quantity_y, "cd")
    } else if (type == "ps") {
      utility_per_dollar_x <- alpha / Px
      utility_per_dollar_y <- (1 - alpha) / Py
      if (utility_per_dollar_x > utility_per_dollar_y) {
        quantity_x <- budget / Px
        quantity_y <- 0
      } else {
        quantity_x <- 0
        quantity_y <- budget / Py
      }
      max_utility <- utility_function(alpha, quantity_x, quantity_y, "ps")
    } else if (type == "pc") {
      quantity_x <- budget / (Px + alpha * Py)
      quantity_y <- alpha * (budget / (Px + alpha * Py))
      max_utility <- utility_function(alpha, quantity_x, quantity_y, "pc")
    } 
    
    # else if (type == "ces") {
    #   objective_function <- function(x) {
    #     y <- (budget - Px*x) / Py
    #     utility_function(alpha, x, y, "ces")
    #   }
    #   lower_bound <- 0
    #   upper_bound <- budget / Px
    #   optimization_result <- optimize(objective_function, interval = c(lower_bound, upper_bound), maximum = TRUE)
    #   quantity_x <- optimization_result$maximum
    #   quantity_y <- (budget - Px*quantity_x) / Py
    #   max_utility <- optimization_result$objective
    # } 
    
    else {
      stop("Unknown utility function type.")
    }
    return(list(max_utility = max_utility, quantity_x = quantity_x, quantity_y = quantity_y))
  }
  
  output$utilityPlot <- renderPlot({
    alpha <- input$alpha
    Px <- input$Px
    Py <- input$Py
    budget <- input$budget
    type <- input$utilityType
    showBudgetLine <- input$showBudgetLine
    showIndifferenceCurve <- input$showIndifferenceCurve
    
    maxutil_all <- maximizeUtility(budget, Px, Py, alpha, type)
    maxutil <- maxutil_all$max_utility
    quantity_x <- maxutil_all$quantity_x
    quantity_y <- maxutil_all$quantity_y
    
    x <- c(seq(1, 100, by = 2), seq(round(quantity_x*0.75, 1), round(quantity_x*1.25, 1), by = .1))
    y <- c(seq(1, 100, by = 2), seq(round(quantity_y*0.75, 1), round(quantity_y*1.25, 1), by = .1))
    grid <- expand.grid(x = x, y = y)
    grid$utility <- utility_function(alpha, grid$x, grid$y, type)
    
    if(showIndifferenceCurve) {
    plot <- ggplot(grid, aes(x = x, y = y)) +
      geom_contour(aes(z = utility), breaks = c(maxutil), color = "red") +
      geom_contour(aes(z = utility), breaks = c(maxutil*0.8, maxutil*1.2), color = "red", linetype = "dashed") +
      coord_cartesian(xlim = c(0, 100), ylim = c(0, 100)) +
      theme_minimal()+
      labs(x = expression(x[1]), y = expression(x[2])) +
      theme(
        axis.title.x = element_text(size = 20),  # Adjust the font size of x-axis label
        axis.title.y = element_text(size = 20)   # Adjust the font size of y-axis label
      )
    
    } else if(showBudgetLine){
      plot <- ggplot(grid, aes(x = x, y = y)) + 
        geom_abline(intercept = budget/Py, slope = -Px/Py, color = "blue") +
        geom_blank() +
        coord_cartesian(xlim = c(0, 100), ylim = c(0, 100)) +
        theme_minimal()+
        labs(x = expression(x[1]), y = expression(x[2])) +
        theme(
          axis.title.x = element_text(size = 20),  # Adjust the font size of x-axis label
          axis.title.y = element_text(size = 20)   # Adjust the font size of y-axis label
        )
      
    } else {
      plot <- ggplot(grid, aes(x = x, y = y)) +
        coord_cartesian(xlim = c(0, 100), ylim = c(0, 100)) +
        theme_minimal()+
        labs(x = expression(x[1]), y = expression(x[2])) + 
        theme(
          axis.title.x = element_text(size = 20),  # Adjust the font size of x-axis label
          axis.title.y = element_text(size = 20)   # Adjust the font size of y-axis label
        )
      }
    
    
    
    if(showBudgetLine && showIndifferenceCurve){
      plot <- plot + geom_abline(intercept = budget/Py, slope = -Px/Py, color = "blue")+
        annotate("segment", x = quantity_x, xend = quantity_x, y = 0, yend = quantity_y, linetype = "dashed")+
        annotate("segment", x = 0, xend = quantity_x, y = quantity_y, yend = quantity_y, linetype = "dashed")+
        annotate("label", x = quantity_x, y = 0, label = round(quantity_x, 2))+
        annotate("label", x = 0, y = quantity_y, label = round(quantity_y, 2))+
        geom_contour(aes(z = utility), breaks = c(maxutil), color = "red") +
        geom_contour(aes(z = utility), breaks = c(maxutil*0.8, maxutil*1.2), color = "red", linetype = "dashed") +
        coord_cartesian(xlim = c(0, 100), ylim = c(0, 100)) +
        theme_minimal()+
        labs(x = expression(x[1]), y = expression(x[2])) +
        theme(
          axis.title.x = element_text(size = 20),  # Adjust the font size of x-axis label
          axis.title.y = element_text(size = 20)   # Adjust the font size of y-axis label
        )
    }
    plot
  })
  
  observeEvent(input$reset, {
    
    updateSliderInput(inputId = "alpha", value = 0.5)
    updateCheckboxInput(inputId = "showBudgetLine", value = FALSE)
    updateCheckboxInput(inputId = "showIndifferenceCurve", value = FALSE)
    updateSliderInput(inputId = "Px", value = 4)
    updateSliderInput(inputId = "Py", value = 2)
    updateSliderInput(inputId = "budget", value = 200)
    
  })
  
  
  
  
  
  output$formula <- renderUI({
    formula <- switch(input$utilityType,
                      "cd" = "$$U(x_1, x_2) = x_1^{\\alpha} x_2^{1-\\alpha}$$",
                      "ps" = "$$U(x_1, x_2) = \\alpha x_1 + (1-\\alpha) x_2$$",
                      "pc" = "$$U(x_1, x_2) = \\min(\\alpha x_1, x_2)$$",
                      
                      
                      #"ces" = "$$U(x, y) = (\\alpha x^{\\rho} + (1-\\alpha) y^{\\rho})^{\\frac{1}{\\rho}}$$",
                
                      "")
    withMathJax("Formel: ", formula)
  })
}

# Run the application
shinyApp(ui = ui, server = server)

Eigenschaften der individuellen Nachfrage

Exploration: Veränderung des Einkommens

Teamarbeit: Gehen Sie zurück auf Folie 31 und spielen Sie mit dem Einkommensparameter herum

  • Wie verändern sich Budgetgerade und Indifferenzkurven?

  • Wie verändert sich das Nachfragebündel?

  • Wie sieht das ganze mit unterschiedlichen Präferenzen aus?

Einkommens-Expansionspfade, Engel-Kurven und Gütertypen

Viele Güter sind normal: bei höherem Budget wird mehr konsumiert

  • Der Einkommens-Expansionspfad im Zweigüterfall und die Engel-Kurve haben eine monoton positive Steigung (siehe nächste Folie)

Einige Güter sind (abschnittsweise) inferior: die Nachfrage reduziert sich bei höherem Budget

  • Dies betrifft vor allem Güter mit niedriger Qualität

  • Die Engel-Kurve fällt und der Einkommens-Expansionspfad ist “gewunden”

Steigt die Nachfrage schneller als das Budget (im Sinne einer Elastizität), spricht man von einem Luxusgut; steigt sie langsamer, ist es ein notwendiges Gut

Grafik: Einkommens-Expansionspfad und Engel-Kurve

Nach Varian, Abbildung 6.3

Exploration: Veränderung der relativen Preise

Teamarbeit: Gehen Sie zurück auf Folie 31 und spielen Sie mit einem der Preise herum

  • Wie verändern sich Budgetgerade und Indifferenzkurven?

  • Wie verändert sich das Nachfragebündel?

  • Wie sieht es mit unterschiedlichen Präferenzen aus?

Anwendung: Butterpreise

EUR/kg, Landesbetrieb Landwirtschaft Hessen, Süddeutsche Butter- und Käsebörse

Anwendung: Gebrauchtwagen

Image

de.statista.com

Die Slutzky Zerlegung

Eine Preissteigerung hat immer zwei Effekte:

  1. Substitutionseffekt: Andere Güter werden relativ billiger, sodass Konsumenten ‘wegsubstituieren’
  • dieser Effekt wirkt immer in diese Richtung
  1. Einkommenseffekt: Das Preisniveau steigt insgesamt an, sodass das reale Budget kleiner wird
  • dieser Effekt kann, wie oben gesehen, den Konsum erhöhen oder senken

Mathematisch kann man leicht die Slutzky Identität herleiten

\[ \underbrace{\frac{\partial x_1(p_1, \ p_2, \bar{m})}{\partial p_1}}_{\text{Gesamteffekt (?)}} \equiv \underbrace{\frac{\partial x_1^S(p_1,\ p_2, \ \bar{x}_1,\bar{x}_2)}{\partial p_1}}_{\text{Substitutionseffekt (-)}} - \underbrace{\frac{\partial x_1(p_1, \ p_2, \bar{m})}{\partial m} \bar{x}_1 }_{\text{Einkommenseffekt (?)}}, \]

  • \(x_i^S\): Nachfrage nach Gut \(i\) wenn das Budget ausgeglichen wird, also bei \(\bar{m}\equiv p_1 \bar{x}_1 + p_2 \bar{x}_2\)

Giffen Güter

Könnte es sein, dass ein Gut stärker nachgefragt wird, wenn sein Preis steigt?

Haben Sie Beispiele?

Slutzky zeigt uns: Prinzipiell kann der Einkommenseffekt so stark sein, dass er den Substitutionseffekt überkompensiert; solche Güter heißen  Giffen Güter

Empirische Evidenz

  • Jensen/Miller (2008): Reis und Fleisch Konsum extrem armer Menschen

    • Feldexperiment in der Provinz Hunan: randomisierte Zuteilung von Gutscheinen für Reis an Haushalte

    • Reiskonsum fiel, insbesondere in Hauhalten mit einem “mittelhohen” Einkommen

Substitute und Komplemente

Bei den Präferenzen haben wir bereits informell von perfekten Substituten und Komplementen gesprochen, dies aber nicht definiert

  • Gut \(i\) ist ein Substitut (Komplement) für Gut \(j\neq i\), wenn \(\partial x_i(\boldsymbol{p},m)/\partial p_j > 0\) \((<0)\)

  • Bei vielen Gütern ist dies eine Matrix mit vielen indirekten Effekten, aber wir beschränken uns auf Brutto-Substitute und -Komplemente

Beispiel: Im Fall der Cobb-Douglas Nachfrage sind Güter weder das eine, noch das andere

\[ x_i(p_i) = \frac{\alpha_i \ m}{p_i} \]

Die Marktnachfrage

Die inverse individuelle Nachfrage

Um zur Marktnachfrage zu gelangen, die wir einem Angebot gegenüberstellen können, verändern wir den Preis eines Gutes ceteris paribus und ermitteln zunächst die individuelle Nachfrage

Bei normalen Gütern fällt diese Funktion, wie Sie bei Ihren Explorationen bereits feststellen konnten

Die Marktnachfrage von \(n\) Konsument:innen ergibt sich als die Summe aller individuellen Nachfragen:

\[ X_i(\boldsymbol{p},\boldsymbol{m}) \equiv \sum_{c=1}^{n} x_i^c(\boldsymbol{p},m^c) \]

Wenn die Präferenzen aller Konsument:innen bestimmte Bedingungen erfüllen, können wir vernachlässigen, dass die Marktnachfrage von der Verteilung der Einkommen abhängt

  • dann sprechen wir von einem repräsentativen Konsumenten mit Budget \(M=\sum m^c\), der sich wie die Gesamtheit der Konsumenten verhält

Grafik: Die inverse Marktnachfragefunktion

#| standalone: true
#| viewerHeight: 600

library(shiny)
library(shinydashboard)
library(ggplot2)
library(graphics)
library(ggpattern)
library(dplyr)
library(purrr)
library(bslib)
library(bs4Dash)




ui <- fluidPage(
  
  
  sidebarLayout(
    sidebarPanel(
      tabsetPanel(
        tabPanel(h5("Einstellungen"),
                 br(),
                 checkboxInput("supp", "Inverses Angebot anzeigen", value = FALSE),
                 
                 checkboxInput("dem", "Inverse Nachfrage anzeigen", value = FALSE),
                 
                 sliderInput("slope_s", "Steigung Angebot", min = 0, max = 10, value = 1, step = 0.5),
                 sliderInput("slope_d", "Steigung Nachfrage", min = -10, max = 0, value = -1, step = 0.5),
                 
                 numericInput("absch_d", "Achsenabschnitt Nachfrage", min = 0, max = 100, value = 75),
                 
                 actionButton("reset", "Reset")
        ),
        
        
        
        tabPanel(h5("Wohlfahrt"),
                 checkboxInput("cs", "Konsumentenrente anzeigen", value = FALSE),
                 
                 checkboxInput("ps", "Produzentenrente anzeigen", value = FALSE),
                 
                 br(),
                 
                 
                 uiOutput('kons_r')   
                 
        ),
        
        
        tabPanel(h5("Steuern"),
                 
                 sliderInput("tax", "Steuerrate t", min = -30, max = 30, value = 0, step = 1),
                 br(),
                 uiOutput("steu_totg")
                 
                 
        )
      )
    ),
    mainPanel(align = "center",
              plotOutput(outputId = "ggwplot", height = "500px", width = "600px"),
    ),
  )
)


server <- function(input, output, session) {
  
  angebot <- function(a_s, x) {
    
    # p_s <- (x - 5)/a_s
    
    p_s <- a_s * x + 5
    
    return(p_s)
  }
  
  nachfrage <- function(a_d, b_d, x){
    
    # p_d <- (x - b_d)/a_d
    
    p_d <- a_d * x + b_d
    
    return(p_d)
    
  }
  
  opt <- function(a_s, a_d, b_d) {
    
    # p_opt <- (b_d - 5) / (a_s - a_d)
    #  x_opt <- a_d * p_opt + b_d
    
    x_opt <- (b_d - 5) / (a_s - a_d)
    p_opt <- a_d * x_opt + b_d 
    
    return(list(p_opt = p_opt, x_opt = x_opt))
  }
  
  
  
  
  
  
  
  
  observeEvent(list(input$tax, input$cs, input$ps, input$supp, input$dem, input$slope_d, input$slope_s, input$absch_d), {
    a_s <- input$slope_s
    a_d <- input$slope_d
    b_d <- input$absch_d
    
    cs <- input$cs
    ps <- input$ps
    
    
    x_v <- seq(0, 100, by = 0.5)
    
    p_s <- angebot(a_s, x_v)
    p_d <- nachfrage(a_d, b_d, x_v)
    t <- input$tax
    
    if (t != 0) {
      
      
      grid <- tibble(
        
        x_val = x_v,
        
        S = p_s + t,
        
        D = p_d
      )
      
      Ergebnisse <- opt(a_s, a_d, b_d)
      #p_s_opt <- (Ergebnisse$p_opt + (t*a_d)/(a_s-a_d))
      # p_d_opt <- (Ergebnisse$p_opt + (t*a_s)/(a_s-a_d))
      
      p_s_opt <- (((t - b_d)/a_d)+(5/a_s))/((1/a_s)-(1/a_d))
      p_d_opt <- p_s_opt + t
      
      x_t <- (p_s_opt - 5)/a_s
      
      # p_opt <- (b_d-5)/(a_s-a_d)
      # x_opt <- a_s * p_opt + 5
      
      x_opt <- (b_d - 5) / (a_s - a_d)
      p_opt <- a_d * x_opt + b_d 
    }
    
    else {
      
      
      grid <- tibble(
        
        x_val = x_v,
        
        S = p_s,
        
        D = p_d
      )
      
      Ergebnisse <- opt(a_s, a_d, b_d)
      p_opt <- Ergebnisse$p_opt 
      x_opt <- Ergebnisse$x_opt
      
      
    }
    
    output$ggwplot <- renderPlot({
      if (input$dem == TRUE && input$supp == TRUE) {
        g_plot <- ggplot(grid) +
          geom_line(aes(x = x_val, y = D, color = "Nachfrage"), size = 1.3) +
          geom_line(aes(x = x_val, y = S, color = "Angebot"), size = ifelse(t != 0, 1, 1.3), linetype = ifelse(t != 0, "dashed", "solid")) +
          scale_color_manual(values = c("Angebot" = "blue", "Nachfrage" = "red")) +
          guides(color = guide_legend(title = "Kurven", position = "bottom", title.position = "left", title.hjust = 0.5)) +
          
          coord_cartesian(xlim = c(-10, 100), ylim = c(-5, 100)) +
          theme_minimal() +
          labs(x = "Menge y", y = "Preis p") +
          theme(
            axis.text = element_text(size = 14),
            axis.title = element_text(size = 16),
            plot.title = element_text(size = 20),
            legend.position = c(0.9, 0.9),  # position -> legend
            legend.justification = c(0.5, 0.5),  # Top right corner
            legend.background = element_rect(fill = "white", color = "black"),
            legend.key = element_rect(fill = "white", color = "white")
          )
        
        
        
      } else if (input$dem == TRUE && input$supp == FALSE) {
        
        g_plot <- ggplot(grid) +
          geom_line(aes(x = x_val, y = D, color = "Nachfrage"), size = 1.3) +
          scale_color_manual(values = c("Nachfrage" = "red")) +
          guides(color = guide_legend(title = "Kurven", position = "bottom", title.position = "left", title.hjust = 0.5)) +
          coord_cartesian(xlim = c(-10, 100), ylim = c(-5, 100)) +
          theme_minimal() +
          labs(x = "Menge y", y = "Preis p") +
          theme(
            axis.text = element_text(size = 14),
            axis.title = element_text(size = 16),
            plot.title = element_text(size = 20),
            legend.position = c(0.9, 0.9),  # Adjust this as necessary to position the legend
            legend.justification = c(0.5, 0.5),  # Top right corner
            legend.background = element_rect(fill = "white", color = "black"),
            legend.key = element_rect(fill = "white", color = "white")
          )
        
      } else if (input$dem == FALSE && input$supp == TRUE ) {
        
        g_plot <- ggplot(grid) +
          geom_line(aes(x = x_val, y = S, color = "Angebot"), size = ifelse(t != 0, 1, 1.3), linetype = ifelse(t != 0, "dashed", "solid")) +
          scale_color_manual(values = c("Angebot" = "blue")) +
          guides(color = guide_legend(title = "Kurven", position = "bottom", title.position = "left", title.hjust = 0.5)) +
          coord_cartesian(xlim = c(-10, 100), ylim = c(-5, 100)) +
          theme_minimal() +
          labs(x = "Menge y", y = "Preis p") +
          theme(
            axis.text = element_text(size = 14),
            axis.title = element_text(size = 16),
            plot.title = element_text(size = 20),
            legend.position = c(0.9, 0.9),  # Adjust this as necessary to position the legend
            legend.justification = c(0.5, 0.5),  # Top right corner
            legend.background = element_rect(fill = "white", color = "black"),
            legend.key = element_rect(fill = "white", color = "white")
          )
        
      } else {
        
        g_plot <- ggplot(grid) +
          geom_line(aes(x = x_val, y = D), color = "white", size = 0.1) +
          coord_cartesian(xlim = c(-5, 100), ylim = c(-5, 100)) +
          theme_minimal() +
          labs(x = "Menge y", y = "Preis p") +
          theme(
            axis.text = element_text(size = 14),
            axis.title = element_text(size = 16),
            plot.title = element_text(size = 20),
            legend.position = c(0.9, 0.9),  # Adjust this as necessary to position the legend
            legend.justification = c(0.5, 0.5),  # Top right corner
            legend.background = element_rect(fill = "white", color = "black"),
            legend.key = element_rect(fill = "white", color = "white")
          )
      }
      
      
      
      if (input$dem && !is.null(p_opt) && cs == TRUE && t == 0) {
        g_plot <- g_plot +
          geom_ribbon_pattern(data = grid %>% filter(x_val <= x_opt),
                              aes(x = x_val, ymin = p_opt, ymax = D, fill = "Konsumentenrente"),
                              # fill = "#FF9999", 
                              pattern = "stripe", 
                              pattern_fill = "red", 
                              pattern_angle = 45, 
                              pattern_density = 0.3, 
                              pattern_spacing = 0.01, 
                              alpha = 0.3) 
        #   annotate("Text", x = -5, y = p_opt + 15, label = "KR", color = "red", size = 7)
        
        
      } else if (input$dem && !is.null(p_opt) && cs == TRUE && t != 0) {
        
        g_plot <- g_plot +
          geom_ribbon_pattern(data = grid %>% filter(x_val <= x_t),
                              aes(x = x_val, ymin = p_d_opt, ymax = D, fill = "Konsumentenrente" ),
                              # fill = "#FF9999", 
                              pattern = "stripe", 
                              pattern_fill = "red", 
                              pattern_angle = 45, 
                              pattern_density = 0.3, 
                              pattern_spacing = 0.01, 
                              alpha = 0.3) 
        
        
      } 
      
      if (input$supp && !is.null(p_opt) && input$ps && t == 0) {
        g_plot <- g_plot +
          geom_ribbon_pattern(data = grid %>% filter(x_val <= x_opt),
                              aes(x = x_val, ymin = S, ymax = p_opt, fill = "Produzentenrente"),
                              #        fill = "#ADD8E6", 
                              pattern = "stripe", 
                              pattern_fill = "blue", 
                              pattern_angle = 135, 
                              pattern_density = 0.3, 
                              pattern_spacing = 0.01, 
                              alpha = 0.3) 
        #  annotate("text", x = -5, y = p_opt - 15, label = "PS", color = "blue", size = 7)
        
        
        
        
      } else if (input$supp && !is.null(p_opt) && input$ps && t != 0) {
        
        g_plot <- g_plot +
          geom_ribbon_pattern(data = grid %>% filter(x_val <= x_t),
                              aes(x = x_val, ymin = S - t, ymax = p_s_opt, fill = "Produzentenrente"),
                              #       fill = "#ADD8E6", 
                              pattern = "stripe", 
                              pattern_fill = "blue", 
                              pattern_angle = 135, 
                              pattern_density = 0.3, 
                              pattern_spacing = 0.01, 
                              alpha = 0.3) 
        
        
      } 
      
      if (input$supp && !is.null(p_opt) && t > 0) {
        g_plot <- g_plot +
          geom_ribbon(data = grid %>% filter(x_val <= x_t),
                      aes(x = x_val, ymin = p_s_opt, ymax = p_opt,  fill = "Steuererträge"),
                      #     fill = "grey", 
                      alpha = 1) +
          geom_ribbon(data = grid %>% filter(x_val <= x_t),
                      aes(x = x_val, ymin = p_opt, ymax = p_d_opt,  fill = "Steuererträge"),
                      #     fill = "grey", 
                      alpha = 1) +
          
          geom_ribbon(data = grid %>% filter(x_val >= x_t & x_val <= x_opt),
                      aes(x = x_val, ymin = S - t, ymax = D, fill = "Wohlfahrtsverlust"),
                      #     fill = "black", 
                      alpha = 1) 
        # annotate("text", x = -5, y = p_opt - 15, label = "PS", color = "blue", size = 7)
      }
      
      
      if (t != 0) {
        g_plot <- g_plot +
          
          geom_line(aes(x = x_val, y = S - t, color = "Angebot"), size = 1.3, linetype = "solid") 
      }  
      
      label1 <- bquote(p[d] ~ "≈")
      label2 <- bquote(p[s] ~ "≈")
      label3 <- bquote(x[t] ~ "≈")
      
      if (t != 0) {
        g_plot <- g_plot +
          geom_segment(aes(x = x_t, xend = x_t, y = -5, yend = p_d_opt), color = "violet", linetype = "longdash", size = 0.7) +
          geom_segment(aes(x = 0, xend = x_t, y = p_d_opt, yend = p_d_opt), color = "violet", linetype = "longdash", size = 0.7) +
          geom_segment(aes(x = 0, xend = x_t, y = p_s_opt, yend = p_s_opt), color = "violet", linetype = "longdash", size = 0.7) +
          annotate("text", x = x_t, y = -5, label = as.expression(bquote(.(label3) ~ .(round(x_t)))), vjust = 1, hjust = 1, color = "violet", size = 5) +
          annotate("text", x = 0, y = p_d_opt, label = as.expression(bquote(.(label1) ~ .(round(p_d_opt)))), vjust = 0.5, hjust = 1, color = "violet", size = 5) +
          annotate("text", x = 0, y = p_s_opt, label = as.expression(bquote(.(label2) ~ .(round(p_s_opt)))), vjust = 0.5, hjust = 1, color = "violet", size = 5)
      }
      
      if ( t < 0) {
        g_plot <- g_plot +
          geom_segment(aes(x = x_t, xend = x_t, y = -5, yend = p_s_opt), color = "violet", linetype = "longdash", size = 0.7)
      }
      
      
      
      if (input$dem == TRUE && input$supp == TRUE) {
        g_plot <- g_plot +
          geom_segment(aes(x = x_opt, xend = x_opt, y = 0, yend = p_opt), color = "orange", linetype = "longdash", size = 0.7) +
          geom_segment(aes(x = 0, xend = x_opt, y = p_opt, yend = p_opt), color = "orange", linetype = "longdash", size = 0.7) +
          annotate("text", x = x_opt, y = 0, label = paste("x* ≈ ", round(x_opt)), vjust = 1, hjust = 0.5, color = "orange", size = 5) +
          annotate("text", x = 0, y = p_opt, label = paste("p* ≈ ", round(p_opt)), vjust = 0.5, hjust = 1, color = "orange", size = 5)
      }
      
      
      g_plot <- g_plot +
        scale_color_manual(
          values = c("Angebot" = "blue", "Nachfrage" = "red"),
          name = "Kurven"
        ) +
        scale_fill_manual(
          values = c("Konsumentenrente" = "#FF9999", "Produzentenrente" = "#ADD8E6", "Steuererträge" = "grey", "Wohlfahrtsverlust" = "black"), name = "") +
        guides(color = guide_legend(title = "Geraden", position = "bottom", title.position = "left", title.hjust = 1))
      
      
      
      
      
      print(g_plot) 
      
    })
  })
  
  
  
  
  observeEvent(input$reset, {
    updateSliderInput(inputId = "slope_d", value = -1)
    updateSliderInput(inputId = "slope_s", value = 1)
    updateSliderInput(inputId = "tax", value = 0)
    
    updateNumericInput(inputId = "absch_d", value = 75)
    updateCheckboxInput(inputId = "cs", value = FALSE)
    updateCheckboxInput(inputId = "ps", value = FALSE)
    
  })
  
  
  kons_r <- reactiveVal(0)
  prod_r <- reactiveVal(0)
  
  observeEvent(list(input$cs, input$ps, input$supp, input$tax, input$dem, input$slope_d, input$slope_s, input$absch_d), {
    a_s <- input$slope_s
    a_d <- input$slope_d
    b_d <- input$absch_d
    Ergebnisse <- opt(a_s, a_d, b_d)
    p_opt <- Ergebnisse$p_opt
    x_opt <- Ergebnisse$x_opt
    t <- input$tax
    
    p_s_opt <- (((t - b_d)/a_d)+(5/a_s))/((1/a_s)-(1/a_d))
    p_d_opt <- p_s_opt + t
    x_t <- (p_s_opt - 5)/a_s
    
    if (input$cs == TRUE && input$supp == TRUE && input$dem == TRUE && t == 0) {
      kons_r(((b_d-p_opt) * x_opt) / 2)
    } else if (input$cs == TRUE && input$supp == TRUE && input$dem == TRUE && t != 0) {
      kons_r(((b_d-p_d_opt) * x_t) / 2)
    } else {
      kons_r(0)
    }
    
    if (input$ps == TRUE && input$supp == TRUE && input$dem == TRUE && t == 0) {
      prod_r((p_opt * x_opt) / 2)
    } else if (input$cs == TRUE && input$supp == TRUE && input$dem == TRUE && t != 0) {
      prod_r((p_s_opt * x_t) / 2)
    } else {
      prod_r(0)
    }
    
  })
  
  
  
  
  output$kons_r <- renderUI({
    
    kons_r_r <- round(kons_r(), digits = 2)
    prod_r_r <- round(prod_r(), digits = 2)
    
    withMathJax(HTML(paste("Konsumentenrente:", kons_r_r, "<br>",
                           "Produzentenrente:", prod_r_r))
    )
  })
  
  
  steu_ber <- reactiveVal(0)
  totg_ber <- reactiveVal(0)
  
  observeEvent(list(input$cs, input$ps, input$supp, input$tax, input$dem, input$slope_d, input$slope_s, input$absch_d), {
    a_s <- input$slope_s
    a_d <- input$slope_d
    b_d <- input$absch_d
    Ergebnisse <- opt(a_s, a_d, b_d)
    p_opt <- Ergebnisse$p_opt
    x_opt <- Ergebnisse$x_opt
    t <- input$tax
    
    p_s_opt <- (((t - b_d)/a_d)+(5/a_s))/((1/a_s)-(1/a_d))
    p_d_opt <- p_s_opt + t
    x_t <- (p_s_opt - 5)/a_s
    
    
    if (input$supp == TRUE && input$dem == TRUE && t > 0) {
      
      steu_ber(-1 * (x_t*(p_d_opt-p_s_opt)))
      
      totg_ber((p_opt-p_s_opt)*(x_opt-x_t)/2 + (p_d_opt-p_opt)*(x_opt-x_t)/2 )
    }
    
    if (input$supp == TRUE && input$dem == TRUE && t < 0) {
      
      steu_ber(x_t*(p_s_opt-p_d_opt))
      
      totg_ber((p_s_opt-p_opt)*(x_t-x_opt)/2 + (p_opt-p_d_opt)*(x_t-x_opt)/2 )
    }
    
  })
  
  
  
  
  output$steu_totg <- renderUI({
    
    steu <- round(steu_ber(), digits = 2)
    totg <- round(totg_ber(), digits = 2)
    
    withMathJax(HTML(paste("Steuereinnahmen:", -steu, "<br>",
                           "Wohlfahrtsverlust:", totg))
    )
  })
  
}

shinyApp(ui = ui, server = server)

Zum Abschluss: Einige nützliche Konzepte

Die Eigenschaften der Nachfragefunktion spielen eine zentrale Rolle in der VWL

  • Preissetzung von Unternehmen

  • Marktreaktionen auf Steuern, Subventionen, Friktionen oder Schocks

  • Wohlfahrtseffekte

Um das besser zu verstehen, brauchen wir ein paar wichtige Konzepte

  • Preiselastizität

  • Einkommenselastizität

  • Konsumentenrente

Die Preiselastizität der Marktnachfrage

Oft sprechen wir aus verschiedenen Gründen von preiselastischer oder preisUNelastischer Nachfrage

  • Unternehmen messen bspw. ihre Marktmacht daran, wie sensitiv ihre Kunden auf Preiserhöhungen reagieren und setzen dementsprechend höhere oder niedrigere Preise
  • Elastizitäten geben an, wie sich eine Größe prozentual verändert, wenn wir eine andere prozentual erhöhen
  • in unserem Fall ist die  Preiselastizität der Nachfrage nach Gut 1

\[ \varepsilon_{X_1,p_1} \equiv \frac{\frac{\partial X_1(p_1)}{X_1(p_1)}*100}{\frac{\partial p_1}{p_1}*100} = \frac{\partial X_1(p_1)}{\partial p_1} \frac{p_1}{X_1(p_1)} \]



Teamarbeit: Gehen Sie zurück auf Folie 44 und verändern Sie die Nachfrageparamater so, dass die Nachfrage elastischer wird!

Beispiel: Nachfrage mit konstanter Preiselastizität

Nehmen wir Cobb-Douglas Präferenzen mit Nachfragefunktion

\[ x_i = \frac{\alpha_i \ m}{p_i} \]

Dann ist die Preiselastizität

\[ \varepsilon_{X_i,p_i} = \frac{\partial x_i(p_i)}{\partial p_i} \frac{p_i}{x_i(p_i)} = \frac{-\alpha_i \ m}{p_i^2} \frac{p_i^2}{\alpha_i \ m} = -1 \]

Cobb-Douglas Präferenzen erzeugen Constant Elasticity of Substitution (CES) Nachfrage

  • Konsument:innen reduzieren ihre Nachfrage immer um ein Prozent, wenn der Preis um ein Prozent steigt

  • CES Präferenzen werden extrem häufig eingesetzt, da sie sehr angenehme Eigenschaften haben

Die Einkommenselastizität

Analog können wir die Einkommenselastizität von Gütern definieren:

\[ \varepsilon_{x_i,m} \equiv \frac{\partial x_i(p_i,m)}{\partial m} \frac{m}{x_i(p_i,m)} \]

Mithilfe dieser Elastizität können wir Güter nun formal kategorisieren

  • Normal: \(\varepsilon_{x_i,m}>0\)
  • Inferior: \(\varepsilon_{x_i,m}<0\)
  • Luxus: \(\varepsilon_{x_i,m}>1\)
  • Notwendige Güter: \(0<\varepsilon_{x_i,m}<1\)

Beispiel: Nachfrage mit konstanter Einkommenselastizität

Wiederum mit Cobb-Dougles Präferenzen und Nachfragefunktion

\[ x_i = \frac{\alpha_i \ m}{p_i} \]

haben wir

\[ \varepsilon_{x_i,m} = \frac{\alpha_i}{p_i} \frac{m}{\frac{\alpha_i \ m}{p_i}} = 1 \]

Jede Einkommenserhöhung um ein Prozent erhöht die Nachfrage nach jedem Gut um ein Prozent

  • Die Engel-Kurve ist eine Gerade mit Steigung \(\alpha_i/p_i\)

  • Diese Präferenzen sind daher homothetisch: die relativen Nachfragen sind unabhängig vom Einkommen

Die Konsumentenrente

Die inverse Marktnachfrage gibt an, welchen Preis Konsument:innen maximal bereit sind zu zahlen, wenn sie eine bestimmte Menge erwerben wollen – diesen Preis nennt man Reservations- oder  Vorbehaltspreis

  • er korrespondiert mit einem bestimmten Nutzenniveau

Der gezahlte Preis entspricht einem bestimmten Nutzenverlust, da andere Güter mit dem verausgabten Geld nicht mehr erworben werden können

Die Konsumentenrente, ein Maß für die Wohlfahrt der Konsumentenseite, kann also über die Differenz zwischen inverser Nachfrage und dem Preis ermittelt werden

  • steigt der Preis, fallen manche Konsumenten aus dem Markt und die Verbliebenen erfahren Nutzeneinbußen

Dieses zentrale Konzept werden wir für die Analyse von Steuern, aber auch von Marktversagen brauchen!

Grafik: Die Konsumentenrente

#| standalone: true
#| viewerHeight: 600

library(shiny)
library(shinydashboard)
library(ggplot2)
library(graphics)
library(ggpattern)
library(dplyr)
library(purrr)
library(bslib)
library(bs4Dash)




ui <- fluidPage(
  
  
  sidebarLayout(
    sidebarPanel(
      tabsetPanel(
        tabPanel(h5("Einstellungen"),
                 br(),
                 checkboxInput("supp", "Inverses Angebot anzeigen", value = FALSE),
                 
                 checkboxInput("dem", "Inverse Nachfrage anzeigen", value = FALSE),
                 
                 sliderInput("slope_s", "Steigung Angebot", min = 0, max = 10, value = 1, step = 0.5),
                 sliderInput("slope_d", "Steigung Nachfrage", min = -10, max = 0, value = -1, step = 0.5),
                 
                 numericInput("absch_d", "Achsenabschnitt Nachfrage", min = 0, max = 100, value = 75),
                 
                 actionButton("reset", "Reset")
        ),
        
        
        
        tabPanel(h5("Wohlfahrt"),
                 checkboxInput("cs", "Konsumentenrente anzeigen", value = FALSE),
                 
                 checkboxInput("ps", "Produzentenrente anzeigen", value = FALSE),
                 
                 br(),
                 
                 
                 uiOutput('kons_r')   
                 
        ),
        
        
        tabPanel(h5("Steuern"),
                 
                 sliderInput("tax", "Steuerrate t", min = -30, max = 30, value = 0, step = 1),
                 br(),
                 uiOutput("steu_totg")
                 
                 
        )
      )
    ),
    mainPanel(align = "center",
              plotOutput(outputId = "ggwplot", height = "500px", width = "600px"),
    ),
  )
)


server <- function(input, output, session) {
  
  angebot <- function(a_s, x) {
    
    # p_s <- (x - 5)/a_s
    
    p_s <- a_s * x + 5
    
    return(p_s)
  }
  
  nachfrage <- function(a_d, b_d, x){
    
    # p_d <- (x - b_d)/a_d
    
    p_d <- a_d * x + b_d
    
    return(p_d)
    
  }
  
  opt <- function(a_s, a_d, b_d) {
    
    # p_opt <- (b_d - 5) / (a_s - a_d)
    #  x_opt <- a_d * p_opt + b_d
    
    x_opt <- (b_d - 5) / (a_s - a_d)
    p_opt <- a_d * x_opt + b_d 
    
    return(list(p_opt = p_opt, x_opt = x_opt))
  }
  
  
  
  
  
  
  
  
  observeEvent(list(input$tax, input$cs, input$ps, input$supp, input$dem, input$slope_d, input$slope_s, input$absch_d), {
    a_s <- input$slope_s
    a_d <- input$slope_d
    b_d <- input$absch_d
    
    cs <- input$cs
    ps <- input$ps
    
    
    x_v <- seq(0, 100, by = 0.5)
    
    p_s <- angebot(a_s, x_v)
    p_d <- nachfrage(a_d, b_d, x_v)
    t <- input$tax
    
    if (t != 0) {
      
      
      grid <- tibble(
        
        x_val = x_v,
        
        S = p_s + t,
        
        D = p_d
      )
      
      Ergebnisse <- opt(a_s, a_d, b_d)
      #p_s_opt <- (Ergebnisse$p_opt + (t*a_d)/(a_s-a_d))
      # p_d_opt <- (Ergebnisse$p_opt + (t*a_s)/(a_s-a_d))
      
      p_s_opt <- (((t - b_d)/a_d)+(5/a_s))/((1/a_s)-(1/a_d))
      p_d_opt <- p_s_opt + t
      
      x_t <- (p_s_opt - 5)/a_s
      
      # p_opt <- (b_d-5)/(a_s-a_d)
      # x_opt <- a_s * p_opt + 5
      
      x_opt <- (b_d - 5) / (a_s - a_d)
      p_opt <- a_d * x_opt + b_d 
    }
    
    else {
      
      
      grid <- tibble(
        
        x_val = x_v,
        
        S = p_s,
        
        D = p_d
      )
      
      Ergebnisse <- opt(a_s, a_d, b_d)
      p_opt <- Ergebnisse$p_opt 
      x_opt <- Ergebnisse$x_opt
      
      
    }
    
    output$ggwplot <- renderPlot({
      if (input$dem == TRUE && input$supp == TRUE) {
        g_plot <- ggplot(grid) +
          geom_line(aes(x = x_val, y = D, color = "Nachfrage"), size = 1.3) +
          geom_line(aes(x = x_val, y = S, color = "Angebot"), size = ifelse(t != 0, 1, 1.3), linetype = ifelse(t != 0, "dashed", "solid")) +
          scale_color_manual(values = c("Angebot" = "blue", "Nachfrage" = "red")) +
          guides(color = guide_legend(title = "Kurven", position = "bottom", title.position = "left", title.hjust = 0.5)) +
          
          coord_cartesian(xlim = c(-10, 100), ylim = c(-5, 100)) +
          theme_minimal() +
          labs(x = "Menge y", y = "Preis p") +
          theme(
            axis.text = element_text(size = 14),
            axis.title = element_text(size = 16),
            plot.title = element_text(size = 20),
            legend.position = c(0.9, 0.9),  # position -> legend
            legend.justification = c(0.5, 0.5),  # Top right corner
            legend.background = element_rect(fill = "white", color = "black"),
            legend.key = element_rect(fill = "white", color = "white")
          )
        
        
        
      } else if (input$dem == TRUE && input$supp == FALSE) {
        
        g_plot <- ggplot(grid) +
          geom_line(aes(x = x_val, y = D, color = "Nachfrage"), size = 1.3) +
          scale_color_manual(values = c("Nachfrage" = "red")) +
          guides(color = guide_legend(title = "Kurven", position = "bottom", title.position = "left", title.hjust = 0.5)) +
          coord_cartesian(xlim = c(-10, 100), ylim = c(-5, 100)) +
          theme_minimal() +
          labs(x = "Menge y", y = "Preis p") +
          theme(
            axis.text = element_text(size = 14),
            axis.title = element_text(size = 16),
            plot.title = element_text(size = 20),
            legend.position = c(0.9, 0.9),  # Adjust this as necessary to position the legend
            legend.justification = c(0.5, 0.5),  # Top right corner
            legend.background = element_rect(fill = "white", color = "black"),
            legend.key = element_rect(fill = "white", color = "white")
          )
        
      } else if (input$dem == FALSE && input$supp == TRUE ) {
        
        g_plot <- ggplot(grid) +
          geom_line(aes(x = x_val, y = S, color = "Angebot"), size = ifelse(t != 0, 1, 1.3), linetype = ifelse(t != 0, "dashed", "solid")) +
          scale_color_manual(values = c("Angebot" = "blue")) +
          guides(color = guide_legend(title = "Kurven", position = "bottom", title.position = "left", title.hjust = 0.5)) +
          coord_cartesian(xlim = c(-10, 100), ylim = c(-5, 100)) +
          theme_minimal() +
          labs(x = "Menge y", y = "Preis p") +
          theme(
            axis.text = element_text(size = 14),
            axis.title = element_text(size = 16),
            plot.title = element_text(size = 20),
            legend.position = c(0.9, 0.9),  # Adjust this as necessary to position the legend
            legend.justification = c(0.5, 0.5),  # Top right corner
            legend.background = element_rect(fill = "white", color = "black"),
            legend.key = element_rect(fill = "white", color = "white")
          )
        
      } else {
        
        g_plot <- ggplot(grid) +
          geom_line(aes(x = x_val, y = D), color = "white", size = 0.1) +
          coord_cartesian(xlim = c(-5, 100), ylim = c(-5, 100)) +
          theme_minimal() +
          labs(x = "Menge y", y = "Preis p") +
          theme(
            axis.text = element_text(size = 14),
            axis.title = element_text(size = 16),
            plot.title = element_text(size = 20),
            legend.position = c(0.9, 0.9),  # Adjust this as necessary to position the legend
            legend.justification = c(0.5, 0.5),  # Top right corner
            legend.background = element_rect(fill = "white", color = "black"),
            legend.key = element_rect(fill = "white", color = "white")
          )
      }
      
      
      
      if (input$dem && !is.null(p_opt) && cs == TRUE && t == 0) {
        g_plot <- g_plot +
          geom_ribbon_pattern(data = grid %>% filter(x_val <= x_opt),
                              aes(x = x_val, ymin = p_opt, ymax = D, fill = "Konsumentenrente"),
                              # fill = "#FF9999", 
                              pattern = "stripe", 
                              pattern_fill = "red", 
                              pattern_angle = 45, 
                              pattern_density = 0.3, 
                              pattern_spacing = 0.01, 
                              alpha = 0.3) 
        #   annotate("Text", x = -5, y = p_opt + 15, label = "KR", color = "red", size = 7)
        
        
      } else if (input$dem && !is.null(p_opt) && cs == TRUE && t != 0) {
        
        g_plot <- g_plot +
          geom_ribbon_pattern(data = grid %>% filter(x_val <= x_t),
                              aes(x = x_val, ymin = p_d_opt, ymax = D, fill = "Konsumentenrente" ),
                              # fill = "#FF9999", 
                              pattern = "stripe", 
                              pattern_fill = "red", 
                              pattern_angle = 45, 
                              pattern_density = 0.3, 
                              pattern_spacing = 0.01, 
                              alpha = 0.3) 
        
        
      } 
      
      if (input$supp && !is.null(p_opt) && input$ps && t == 0) {
        g_plot <- g_plot +
          geom_ribbon_pattern(data = grid %>% filter(x_val <= x_opt),
                              aes(x = x_val, ymin = S, ymax = p_opt, fill = "Produzentenrente"),
                              #        fill = "#ADD8E6", 
                              pattern = "stripe", 
                              pattern_fill = "blue", 
                              pattern_angle = 135, 
                              pattern_density = 0.3, 
                              pattern_spacing = 0.01, 
                              alpha = 0.3) 
        #  annotate("text", x = -5, y = p_opt - 15, label = "PS", color = "blue", size = 7)
        
        
        
        
      } else if (input$supp && !is.null(p_opt) && input$ps && t != 0) {
        
        g_plot <- g_plot +
          geom_ribbon_pattern(data = grid %>% filter(x_val <= x_t),
                              aes(x = x_val, ymin = S - t, ymax = p_s_opt, fill = "Produzentenrente"),
                              #       fill = "#ADD8E6", 
                              pattern = "stripe", 
                              pattern_fill = "blue", 
                              pattern_angle = 135, 
                              pattern_density = 0.3, 
                              pattern_spacing = 0.01, 
                              alpha = 0.3) 
        
        
      } 
      
      if (input$supp && !is.null(p_opt) && t > 0) {
        g_plot <- g_plot +
          geom_ribbon(data = grid %>% filter(x_val <= x_t),
                      aes(x = x_val, ymin = p_s_opt, ymax = p_opt,  fill = "Steuererträge"),
                      #     fill = "grey", 
                      alpha = 1) +
          geom_ribbon(data = grid %>% filter(x_val <= x_t),
                      aes(x = x_val, ymin = p_opt, ymax = p_d_opt,  fill = "Steuererträge"),
                      #     fill = "grey", 
                      alpha = 1) +
          
          geom_ribbon(data = grid %>% filter(x_val >= x_t & x_val <= x_opt),
                      aes(x = x_val, ymin = S - t, ymax = D, fill = "Wohlfahrtsverlust"),
                      #     fill = "black", 
                      alpha = 1) 
        # annotate("text", x = -5, y = p_opt - 15, label = "PS", color = "blue", size = 7)
      }
      
      
      if (t != 0) {
        g_plot <- g_plot +
          
          geom_line(aes(x = x_val, y = S - t, color = "Angebot"), size = 1.3, linetype = "solid") 
      }  
      
      label1 <- bquote(p[d] ~ "≈")
      label2 <- bquote(p[s] ~ "≈")
      label3 <- bquote(x[t] ~ "≈")
      
      if (t != 0) {
        g_plot <- g_plot +
          geom_segment(aes(x = x_t, xend = x_t, y = -5, yend = p_d_opt), color = "violet", linetype = "longdash", size = 0.7) +
          geom_segment(aes(x = 0, xend = x_t, y = p_d_opt, yend = p_d_opt), color = "violet", linetype = "longdash", size = 0.7) +
          geom_segment(aes(x = 0, xend = x_t, y = p_s_opt, yend = p_s_opt), color = "violet", linetype = "longdash", size = 0.7) +
          annotate("text", x = x_t, y = -5, label = as.expression(bquote(.(label3) ~ .(round(x_t)))), vjust = 1, hjust = 1, color = "violet", size = 5) +
          annotate("text", x = 0, y = p_d_opt, label = as.expression(bquote(.(label1) ~ .(round(p_d_opt)))), vjust = 0.5, hjust = 1, color = "violet", size = 5) +
          annotate("text", x = 0, y = p_s_opt, label = as.expression(bquote(.(label2) ~ .(round(p_s_opt)))), vjust = 0.5, hjust = 1, color = "violet", size = 5)
      }
      
      if ( t < 0) {
        g_plot <- g_plot +
          geom_segment(aes(x = x_t, xend = x_t, y = -5, yend = p_s_opt), color = "violet", linetype = "longdash", size = 0.7)
      }
      
      
      
      if (input$dem == TRUE && input$supp == TRUE) {
        g_plot <- g_plot +
          geom_segment(aes(x = x_opt, xend = x_opt, y = 0, yend = p_opt), color = "orange", linetype = "longdash", size = 0.7) +
          geom_segment(aes(x = 0, xend = x_opt, y = p_opt, yend = p_opt), color = "orange", linetype = "longdash", size = 0.7) +
          annotate("text", x = x_opt, y = 0, label = paste("x* ≈ ", round(x_opt)), vjust = 1, hjust = 0.5, color = "orange", size = 5) +
          annotate("text", x = 0, y = p_opt, label = paste("p* ≈ ", round(p_opt)), vjust = 0.5, hjust = 1, color = "orange", size = 5)
      }
      
      
      g_plot <- g_plot +
        scale_color_manual(
          values = c("Angebot" = "blue", "Nachfrage" = "red"),
          name = "Kurven"
        ) +
        scale_fill_manual(
          values = c("Konsumentenrente" = "#FF9999", "Produzentenrente" = "#ADD8E6", "Steuererträge" = "grey", "Wohlfahrtsverlust" = "black"), name = "") +
        guides(color = guide_legend(title = "Geraden", position = "bottom", title.position = "left", title.hjust = 1))
      
      
      
      
      
      print(g_plot) 
      
    })
  })
  
  
  
  
  observeEvent(input$reset, {
    updateSliderInput(inputId = "slope_d", value = -1)
    updateSliderInput(inputId = "slope_s", value = 1)
    updateSliderInput(inputId = "tax", value = 0)
    
    updateNumericInput(inputId = "absch_d", value = 75)
    updateCheckboxInput(inputId = "cs", value = FALSE)
    updateCheckboxInput(inputId = "ps", value = FALSE)
    
  })
  
  
  kons_r <- reactiveVal(0)
  prod_r <- reactiveVal(0)
  
  observeEvent(list(input$cs, input$ps, input$supp, input$tax, input$dem, input$slope_d, input$slope_s, input$absch_d), {
    a_s <- input$slope_s
    a_d <- input$slope_d
    b_d <- input$absch_d
    Ergebnisse <- opt(a_s, a_d, b_d)
    p_opt <- Ergebnisse$p_opt
    x_opt <- Ergebnisse$x_opt
    t <- input$tax
    
    p_s_opt <- (((t - b_d)/a_d)+(5/a_s))/((1/a_s)-(1/a_d))
    p_d_opt <- p_s_opt + t
    x_t <- (p_s_opt - 5)/a_s
    
    if (input$cs == TRUE && input$supp == TRUE && input$dem == TRUE && t == 0) {
      kons_r(((b_d-p_opt) * x_opt) / 2)
    } else if (input$cs == TRUE && input$supp == TRUE && input$dem == TRUE && t != 0) {
      kons_r(((b_d-p_d_opt) * x_t) / 2)
    } else {
      kons_r(0)
    }
    
    if (input$ps == TRUE && input$supp == TRUE && input$dem == TRUE && t == 0) {
      prod_r((p_opt * x_opt) / 2)
    } else if (input$cs == TRUE && input$supp == TRUE && input$dem == TRUE && t != 0) {
      prod_r((p_s_opt * x_t) / 2)
    } else {
      prod_r(0)
    }
    
  })
  
  
  
  
  output$kons_r <- renderUI({
    
    kons_r_r <- round(kons_r(), digits = 2)
    prod_r_r <- round(prod_r(), digits = 2)
    
    withMathJax(HTML(paste("Konsumentenrente:", kons_r_r, "<br>",
                           "Produzentenrente:", prod_r_r))
    )
  })
  
  
  steu_ber <- reactiveVal(0)
  totg_ber <- reactiveVal(0)
  
  observeEvent(list(input$cs, input$ps, input$supp, input$tax, input$dem, input$slope_d, input$slope_s, input$absch_d), {
    a_s <- input$slope_s
    a_d <- input$slope_d
    b_d <- input$absch_d
    Ergebnisse <- opt(a_s, a_d, b_d)
    p_opt <- Ergebnisse$p_opt
    x_opt <- Ergebnisse$x_opt
    t <- input$tax
    
    p_s_opt <- (((t - b_d)/a_d)+(5/a_s))/((1/a_s)-(1/a_d))
    p_d_opt <- p_s_opt + t
    x_t <- (p_s_opt - 5)/a_s
    
    
    if (input$supp == TRUE && input$dem == TRUE && t > 0) {
      
      steu_ber(-1 * (x_t*(p_d_opt-p_s_opt)))
      
      totg_ber((p_opt-p_s_opt)*(x_opt-x_t)/2 + (p_d_opt-p_opt)*(x_opt-x_t)/2 )
    }
    
    if (input$supp == TRUE && input$dem == TRUE && t < 0) {
      
      steu_ber(x_t*(p_s_opt-p_d_opt))
      
      totg_ber((p_s_opt-p_opt)*(x_t-x_opt)/2 + (p_opt-p_d_opt)*(x_t-x_opt)/2 )
    }
    
  })
  
  
  
  
  output$steu_totg <- renderUI({
    
    steu <- round(steu_ber(), digits = 2)
    totg <- round(totg_ber(), digits = 2)
    
    withMathJax(HTML(paste("Steuereinnahmen:", -steu, "<br>",
                           "Wohlfahrtsverlust:", totg))
    )
  })
  
}

shinyApp(ui = ui, server = server)

Wiederholungsfragen

  • Erläutern Sie, welche Güterbündel sich Nachfrager überhaupt leisten können und von welchen Determinanten diese Menge abhängt

  • Gehen Sie alle Nutzenfunktionen anhand der interaktiven Grafik durch und erläutern Sie, warum die Indifferenzkurven die jeweilige Form annehmen

  • Wie findet man die optimale Nachfrage? Welche Herangehensweisen gibt es?

  • Nehmen Sie eine bestimmte Klasse von Nutzenfunktionen und versuchen Sie, mithilfe einer interaktiven Grafik Einkommens-Expansionspfade, Engel-Kurven und Nachfragefunktionen zu konstruieren

  • Suchen Sie sich einen Partner und erklären dieser Person die Begriffe “Preiselastizität”, “Einkommenselastizität” und “Konsumentenrente”