2017-05-20 1 views
1

Ich möchte Operationen auf eine Datenrahmen (tibble) -Spalte anwenden, die S3-listähnliche Objekte enthält, um zu handeln auf einem der benannten Elemente von jedem Objekt in der Spalte. Wie am Ende der Frage, ich habe dies funktioniert mit sapply() innerhalb mutate(), aber das scheint wie es unnötig sein sollte.Zugriff auf Werte in S3-Listen-ähnlichen Objekten mit mutate() (oder Extrahieren von Werten aus S3-Objekten)

Wo Informationen in Spalten mit atomaren Daten gespeichert sind, funktionieren dplyr-Funktionen wie mutate() wie erwartet. Dies funktioniert zum Beispiel:

library(dplyr) 
people_cols <- tibble(name = c("Fiona Foo", "Barry Bar", "Basil Baz"), 
        height_mm = c(1750, 1700, 1800), 
        weight_kg = c(75, 73, 74)) %>% 
    mutate(height_inch = height_mm/25.4) 
people_cols 
# # A tibble: 3 × 4 
# name   height_mm weight_kg height_inch 
# <chr>   <dbl>  <dbl>  <dbl> 
# 1 Fiona Foo  1750  75   68.89764 
# 2 Barry Bar  1700  73   66.92913 
# 3 Basil Baz  1800  74   70.86614 

Aber ich möchte mit Daten in S3-Listenobjekte arbeiten. Hier ist ein Spielzeug Beispiel:

person_stats <- function(name, height_mm, weight_kg) { 
    this_person <- structure(list(name = name, 
           height_mm = height_mm, 
           weight_kg = weight_kg), 
          class = "person_stats") 
} 

fiona <- person_stats("Fiona Foo", 1750, 75) 
barry <- person_stats("Barry Bar", 1700, 73) 
basil <- person_stats("Basil Baz", 1800, 74) 

fiona$height_mm 
# [1] 1750 

ich diese Objekte in eine tibble Spalte so sagen kann:

people <- tibble(personstat = list(fiona, barry, basil)) 

people 
# # A tibble: 3 × 1 
# personstat 
#  <list> 
# 1 <S3: person_stats> 
# 2 <S3: person_stats> 
# 3 <S3: person_stats> 

Aber wenn ich versuche, mutieren() auf der Säule zu verwenden, um diese Objekte enthält bekomme ich Fehler :

people <- tibble(personstat = list(fiona, barry, basil)) %>% 
    mutate(height_inch = personstat$height_mm/25.4) 
# Error in mutate_impl(.data, dots) : object 'personstat' not found 

der Versuch, es so einfach wie möglich zu halten - wenn ich auch die genannten Elemente auf ihre eigenen verweisen können dann könnte ich sie zumindest in eine neue Spalte zu bekommen, und von dann das tun, was Operationen o n ihnen:

people <- tibble(personstat = list(fiona, barry, basil)) %>% 
    mutate(height_mm = personstat$height_mm) 
# Error in mutate_impl(.data, dots) : 
# Unsupported type NILSXP for column "height_mm" 

Beachten Sie die verschiedenen Fehler, was interessant ist - es ist nicht mehr beschweren sich über die Spalte zu finden, nur mit dem benannten Punkt kämpfen.

Ich kann es bekommen Basisfunktionen arbeiten mit, cbind() und sapply() mit [[ als Funktion:

people <- tibble(personstat = list(fiona, barry, basil)) %>% 
    cbind(height_mm = sapply(.$personstat, '[[', name="height_mm")) 

people 
#   personstat height_mm 
# 1 Fiona Foo, 1750, 75  1750 
# 2 Barry Bar, 1700, 73  1700 
# 3 Basil Baz, 1800, 74  1800 

aber, dass die tibble-iness verliert.

class(people) 
# [1] "data.frame" 

Und schließlich, das mich dazu bekam, was funktioniert, aber es fühlt sich an wie mit sapply() Art trifft nicht den Punkt von dplyr mutate(), die ich denke, sollte unten eine Spalte den ganzen Weg arbeiten, ohne dass zu benötigen:

people <- tibble(personstat = list(fiona, barry, basil)) %>% 
    mutate(height_mm = sapply(.$personstat, '[[', name="height_mm")) 
people 
# A tibble: 3 x 2 
#   personstat height_mm 
#    <list>  <dbl> 
# 1 <S3: person_stats>  1750 
# 2 <S3: person_stats>  1700 
# 3 <S3: person_stats>  1800 

gibt es eine Möglichkeit mutate() der Verwendung die Ausgabe, wie oben zu bekommen, ohne wie sapply() auf etwas verlassen zu müssen? Oder, in der Tat, andere sinnvolle Möglichkeiten, um benannte Werte aus listenähnlichen S3-Objekten zu extrahieren, die in einer Spalte eines tibbles gespeichert sind?

Antwort

2

rowwise solchen Fall behandeln kann:

people <- tibble(personstat = list(fiona, barry, basil)) 

people %>% 
    rowwise() %>% 
    mutate(height_mm = personstat$height_mm) 
# # A tibble: 3 × 2 
#   personstat height_mm 
# <list>  <dbl> 
# 1 <S3: person_stats>  1750 
# 2 <S3: person_stats>  1700 
# 3 <S3: person_stats>  1800 

people %>% 
    rowwise() %>% 
    mutate(height_inch = personstat$height_mm/25.4) 

# # A tibble: 3 × 2 
#   personstat height_inch 
# <list>  <dbl> 
# 1 <S3: person_stats> 68.89764 
# 2 <S3: person_stats> 66.92913 
# 3 <S3: person_stats> 70.86614 
+0

Danke dafür. Ich würde 'rowwise()' nicht bemerken, aber es sieht nur nach dem Job aus. Allerdings bekomme ich einige Fehler bei dem, was Sie vorschlagen. Die Top-Version funktioniert, aber die Version mit der 'height_inch =' Berechnung löst einen Fehler aus. Ich benutze dplyr v0.5.0 (zuletzt auf CRAN). Leider installiert die GitHub-Version momentan nicht für mich. Vielleicht verwenden Sie eine neuere/Entwicklungsversion? – jamse

+0

Die Fehlermeldung lautet 'Fehler in muate_impl (.data, dots): Objekt' personstat 'nicht gefunden'. – jamse

+0

@jamse, ich benutze dplyr 0.6.0 pre-release (erhältlich von github) im obigen Code. Ich sehe den gleichen Fehler mit v0.5.0. Es könnte ein Fehler für v0.5.0 sein. Ich bin nicht sicher. – mt1022

1

Wenn Sie es in der tidyverse behalten möchten könnten Sie purrr::map_dbl hier verwenden:

library(tidyverse)  
people %>% mutate(height = map_dbl(personstat, "height_mm")) 
+1

Dank dafür. Ich habe die andere Antwort akzeptiert, weil es nur dplyr und ein wenig klarer für mein Auge ist, aber das funktioniert auch. Für diejenigen, die eine 'map_dbl'-Version verwenden möchten, können Sie sowohl die Berechnung als auch das Extrahieren der Variablen wie folgt durchführen:' people%>% muate (height_inch = map_dbl (personstat, height_mm ")/25.4) ' – jamse

Verwandte Themen