Jak zrobić świetny powtarzalny przykład R.
Podczas omawiania wydajności ze współpracownikami, nauczania, wysyłania raportów o błędach lub wyszukiwania wskazówek dotyczących list mailingowych, a tutaj w witrynie Stack Overflow, często zadawane są powtarzalne przykłady, które zawsze są pomocne.
Jakie masz wskazówki, jak stworzyć doskonały przykład? Jak wkleić struktury danych z r w formacie tekstowym? Jakie inne informacje powinieneś dołączyć?
Czy istnieją inne sztuczki oprócz korzystania dput()
, dump()
albo structure()
? Kiedy należy dołączyć oświadczenia library()
lub require()
? Który zastrzeżone słów należy unikać, w uzupełnieniu do c
, df
, data
, itd.?
W jaki sposób można zrobić wielki r powtarzalne przykład?
Odpowiedzi
Minimalny powtarzalne przykład składa się z następujących elementów:
- minimalny zbiór danych, niezbędny do zademonstrowania problemu
- minimalny możliwy do wykonania kod niezbędny do odtworzenia błędu, który można uruchomić na danym zbiorze danych
- niezbędne informacje o używanych pakietach, wersji R i systemie, na którym jest uruchamiany.
- w przypadku procesów losowych ziarno (ustalone przez
set.seed()
) dla odtwarzalności 1
Przykłady dobrych, minimalnych, powtarzalnych przykładów można znaleźć w plikach pomocy używanej funkcji. Ogólnie rzecz biorąc, cały podany tam kod spełnia wymagania minimalnego powtarzalnego przykładu: dane są dostarczane, minimalny kod jest dostarczany i wszystko jest możliwe do uruchomienia. Spójrz także na pytania dotyczące przepełnienia stosu z wieloma pozytywnymi opiniami.
Tworzenie minimalnego zbioru danych
W większości przypadków można to łatwo zrobić, po prostu dostarczając ramkę wektora / danych z pewnymi wartościami. Możesz też użyć jednego z wbudowanych zestawów danych, które są dostarczane z większością pakietów.
Pełną listę wbudowanych zestawów danych można zobaczyć za pomocą library(help = "datasets")
. Każdy zbiór danych ma krótki opis i można uzyskać więcej informacji, na przykład ?mtcars
gdzie „mtcars” jest jednym ze zbiorów danych na liście. Inne pakiety mogą zawierać dodatkowe zbiory danych.
Tworzenie wektora jest łatwe. Czasami trzeba dodać do tego trochę losowości i jest do tego cała liczba funkcji. sample()
może losować wektor lub dać losowy wektor zawierający tylko kilka wartości. letters
jest użytecznym wektorem zawierającym alfabet. Można to wykorzystać do tworzenia czynników.
Kilka przykładów:
- wartości losowe:
x <- rnorm(10)
dla rozkładu normalnego,x <- runif(10)
dla rozkładu równomiernego, ... - permutacja niektórych wartości:
x <- sample(1:10)
dla wektora 1:10 w kolejności losowej. - czynnik losowy:
x <- sample(letters[1:4], 20, replace = TRUE)
Do matryc można użyć matrix()
np .:
matrix(1:10, ncol = 2)
Tworzenie ramek danych można wykonać za pomocą data.frame()
. Należy zwrócić uwagę na nazwanie wpisów w ramce danych i nie komplikowanie jej zbytnio.
Przykład :
set.seed(1)
Data <- data.frame(
X = sample(1:10),
Y = sample(c("yes", "no"), 10, replace = TRUE)
)
W przypadku niektórych pytań mogą być potrzebne określone formaty. Dla nich, można użyć dowolnego z określonych as.someType
funkcji: as.factor
, as.Date
, as.xts
, ... To w połączeniu z wektorem i / lub ramka danych sztuczek.
Skopiuj swoje dane
Jeśli masz jakieś dane, które byłyby zbyt trudne do skonstruowania za pomocą tych wskazówek, to zawsze można zrobić podzbiór oryginalnego danych, używając head()
, subset()
lub indeksy. Następnie użyj, dput()
aby dać nam coś, co można natychmiast wstawić do R:
> dput(iris[1:4, ]) # first four rows of the iris data set
structure(list(Sepal.Length = c(5.1, 4.9, 4.7, 4.6), Sepal.Width = c(3.5,
3, 3.2, 3.1), Petal.Length = c(1.4, 1.4, 1.3, 1.5), Petal.Width = c(0.2,
0.2, 0.2, 0.2), Species = structure(c(1L, 1L, 1L, 1L), .Label = c("setosa",
"versicolor", "virginica"), class = "factor")), .Names = c("Sepal.Length",
"Sepal.Width", "Petal.Length", "Petal.Width", "Species"), row.names = c(NA,
4L), class = "data.frame")
Jeśli ramka danych ma czynnik z wieloma poziomami, dane dput
wyjściowe mogą być nieporęczne, ponieważ nadal będą zawierać listę wszystkich możliwych poziomów czynników, nawet jeśli nie są one obecne w podzbiorze danych. Aby rozwiązać ten problem, możesz użyć droplevels()
funkcji. Zauważ poniżej, jak gatunek jest czynnikiem tylko na jednym poziomie:
> dput(droplevels(iris[1:4, ]))
structure(list(Sepal.Length = c(5.1, 4.9, 4.7, 4.6), Sepal.Width = c(3.5,
3, 3.2, 3.1), Petal.Length = c(1.4, 1.4, 1.3, 1.5), Petal.Width = c(0.2,
0.2, 0.2, 0.2), Species = structure(c(1L, 1L, 1L, 1L), .Label = "setosa",
class = "factor")), .Names = c("Sepal.Length", "Sepal.Width",
"Petal.Length", "Petal.Width", "Species"), row.names = c(NA,
4L), class = "data.frame")
Podczas używania dput
możesz również chcieć uwzględnić tylko odpowiednie kolumny:
> dput(mtcars[1:3, c(2, 5, 6)]) # first three rows of columns 2, 5, and 6
structure(list(cyl = c(6, 6, 4), drat = c(3.9, 3.9, 3.85), wt = c(2.62,
2.875, 2.32)), row.names = c("Mazda RX4", "Mazda RX4 Wag", "Datsun 710"
), class = "data.frame")
Innym zastrzeżeniem dput
jest to, że nie będzie działać dla data.table
obiektów z kluczem lub zgrupowanych tbl_df
(klas grouped_df
) z dplyr
. W takich przypadkach można przekształcić z powrotem do regularnego ramki danych przed udostępnianie dput(as.data.frame(my_data))
.
W najgorszym przypadku możesz podać reprezentację tekstową, którą można odczytać za pomocą text
parametru read.table
:
zz <- "Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1 5.1 3.5 1.4 0.2 setosa
2 4.9 3.0 1.4 0.2 setosa
3 4.7 3.2 1.3 0.2 setosa
4 4.6 3.1 1.5 0.2 setosa
5 5.0 3.6 1.4 0.2 setosa
6 5.4 3.9 1.7 0.4 setosa"
Data <- read.table(text=zz, header = TRUE)
Tworzenie minimalnego kodu
To powinna być łatwa część, ale często tak nie jest. To, czego nie powinieneś robić, to:
- dodać wszelkiego rodzaju konwersje danych. Upewnij się, że podane dane są już w odpowiednim formacie (chyba że jest to oczywiście problem)
- skopiuj i wklej całą funkcję / fragment kodu, który powoduje błąd. Najpierw spróbuj zlokalizować dokładnie, które wiersze powodują błąd. Najczęściej sam się przekonasz, na czym polega problem.
Co powinieneś zrobić, to:
- dodaj, które pakiety powinny być używane, jeśli używasz (używając
library()
) - jeśli otwierasz połączenia lub tworzysz pliki, dodaj kod, aby je zamknąć lub usunąć pliki (za pomocą
unlink()
) - jeśli zmienisz opcje, upewnij się, że kod zawiera instrukcję, aby przywrócić je z powrotem do oryginalnych. (np.
op <- par(mfrow=c(1,2)) ...some code... par(op)
) - test uruchom kod w nowej, pustej sesji języka R, aby upewnić się, że kod można uruchomić. Ludzie powinni móc po prostu skopiować i wkleić twoje dane i kod w konsoli i uzyskać dokładnie to samo, co masz.
Podaj dodatkowe informacje
W większości przypadków wystarczy wersja R i system operacyjny. Kiedy pojawiają się konflikty z pakietami, podanie wyniku sessionInfo()
może naprawdę pomóc. Mówiąc o połączeniach z innymi aplikacjami (czy to przez ODBC, czy cokolwiek innego), należy również podać numery wersji dla tych aplikacji, a jeśli to możliwe, również niezbędne informacje o konfiguracji.
Jeśli używasz R w R Studio, użycie rstudioapi::versionInfo()
może być pomocne w zgłoszeniu wersji RStudio.
Jeśli masz problem z określonym pakietem, możesz chcieć podać wersję pakietu, podając wynik polecenia packageVersion("name of the package")
.
1 Uwaga: wynik set.seed()
różni się między R> 3.6.0 a poprzednimi wersjami. Określ, której wersji R użyłeś w losowym procesie, i nie zdziw się, jeśli uzyskasz nieco inne wyniki podczas odpowiedzi na stare pytania. Aby uzyskać ten sam wynik w takich przypadkach, możesz użyć funkcji RNGversion()
przed set.seed()
(np RNGversion("3.5.2")
. :) .
(Oto moja rada z artykułu Jak napisać powtarzalny przykład . Starałem się, aby był krótki, ale słodki)
Jak napisać powtarzalny przykład.
Najprawdopodobniej uzyskasz dobrą pomoc w rozwiązaniu problemu z językiem R, jeśli podasz powtarzalny przykład. Odtwarzalny przykład pozwala komuś innemu odtworzyć Twój problem, po prostu kopiując i wklejając kod R.
Aby Twój przykład był odtwarzalny, musisz uwzględnić cztery rzeczy: wymagane pakiety, dane, kod i opis środowiska języka R.
Pakiety powinny być ładowane w górnej części skryptu, aby łatwo było zobaczyć, które z nich są potrzebne w przykładzie.
Najłatwiejszym sposobem uwzględnienia danych w wiadomości e-mail lub w pytaniu dotyczącym przepełnienia stosu jest
dput()
wygenerowanie kodu R w celu jego odtworzenia. Na przykład, aby odtworzyćmtcars
zestaw danych w R, wykonałbym następujące kroki:- Uruchom
dput(mtcars)
w R. - Skopiuj wynik
- W moim odtwarzalnym skrypcie wpisz,
mtcars <-
a następnie wklej.
- Uruchom
Poświęć trochę czasu, aby upewnić się, że Twój kod jest łatwy do odczytania dla innych:
upewnij się, że użyłeś spacji, a nazwy zmiennych są zwięzłe, ale zawierają informacje
użyj komentarzy, aby wskazać, gdzie leży twój problem
postaraj się usunąć wszystko, co nie jest związane z problemem.
Im krótszy jest twój kod, tym łatwiej jest go zrozumieć.
Uwzględnij wyniki
sessionInfo()
w komentarzu w swoim kodzie. To podsumowuje twoje środowisko R i ułatwia sprawdzenie, czy używasz nieaktualnego pakietu.
Możesz sprawdzić, czy rzeczywiście utworzyłeś powtarzalny przykład, uruchamiając nową sesję języka R i wklejając skrypt.
Przed umieszczeniem całego kodu w e-mailu rozważ umieszczenie go na Gist github . Dzięki temu Twój kod będzie dobrze podświetlony i nie musisz się martwić, że cokolwiek zostanie zniekształcone przez system poczty elektronicznej.
Osobiście wolę „jeden” wkład. Coś w stylu:
my.df <- data.frame(col1 = sample(c(1,2), 10, replace = TRUE),
col2 = as.factor(sample(10)), col3 = letters[1:10],
col4 = sample(c(TRUE, FALSE), 10, replace = TRUE))
my.list <- list(list1 = my.df, list2 = my.df[3], list3 = letters)
Struktura danych powinna naśladować ideę problemu pisarza, a nie dokładną strukturę dosłowną. Naprawdę doceniam to, gdy zmienne nie zastępują moich własnych zmiennych ani nie daj Boże, funkcje (takie jak df
).
Alternatywnie można pójść na kilka rogów i wskazać na istniejący zestaw danych, na przykład:
library(vegan)
data(varespec)
ord <- metaMDS(varespec)
Nie zapomnij wspomnieć o specjalnych pakietach, których możesz używać.
Jeśli próbujesz zademonstrować coś na większych obiektach, możesz spróbować
my.df2 <- data.frame(a = sample(10e6), b = sample(letters, 10e6, replace = TRUE))
Jeśli pracujesz z danymi przestrzennymi za pośrednictwem raster
pakietu, możesz wygenerować losowe dane. Wiele przykładów można znaleźć w winiecie pakietu, ale tutaj jest mały samorodek.
library(raster)
r1 <- r2 <- r3 <- raster(nrow=10, ncol=10)
values(r1) <- runif(ncell(r1))
values(r2) <- runif(ncell(r2))
values(r3) <- runif(ncell(r3))
s <- stack(r1, r2, r3)
Jeśli potrzebujesz jakiegoś obiektu przestrzennego zaimplementowanego w programie sp
, możesz pobrać niektóre zestawy danych za pośrednictwem plików zewnętrznych (takich jak plik kształtu ESRI) w pakietach „przestrzennych” (zobacz widok przestrzenny w widokach zadań).
library(rgdal)
ogrDrivers()
dsn <- system.file("vectors", package = "rgdal")[1]
ogrListLayers(dsn)
ogrInfo(dsn=dsn, layer="cities")
cities <- readOGR(dsn=dsn, layer="cities")
Zainspirowany tym postem, teraz używam przydatnej funkcji,
reproduce(<mydata>)
gdy muszę publikować w StackOverflow.
SZYBKA INSTRUKCJA
Jeśli myData
jest to nazwa obiektu do odtworzenia, uruchom w R:
install.packages("devtools")
library(devtools)
source_url("https://raw.github.com/rsaporta/pubR/gitbranch/reproduce.R")
reproduce(myData)
Detale:
Ta funkcja jest inteligentnym opakowaniem dput
i wykonuje następujące czynności:
- automatycznie próbkuje duży zestaw danych (na podstawie rozmiaru i klasy. Wielkość próbki można dostosować)
- tworzy
dput
wynik - umożliwia określenie, które kolumny mają zostać wyeksportowane
- dołącza się do przodu,
objName <- ...
dzięki czemu można go łatwo skopiować + wkleić, ale ... - Jeśli pracujesz na komputerze Mac, dane wyjściowe są automatycznie kopiowane do schowka, dzięki czemu możesz je po prostu uruchomić, a następnie wkleić do pytania.
Źródło jest dostępne tutaj:
- Github - pubR / reproduce.R
Przykład:
# sample data
DF <- data.frame(id=rep(LETTERS, each=4)[1:100], replicate(100, sample(1001, 100)), Class=sample(c("Yes", "No"), 100, TRUE))
DF wynosi około 100 x 102. Chcę pobrać próbkę z 10 wierszy i kilku określonych kolumn
reproduce(DF, cols=c("id", "X1", "X73", "Class")) # I could also specify the column number.
Daje następujący wynik:
This is what the sample looks like:
id X1 X73 Class
1 A 266 960 Yes
2 A 373 315 No Notice the selection split
3 A 573 208 No (which can be turned off)
4 A 907 850 Yes
5 B 202 46 Yes
6 B 895 969 Yes <~~~ 70 % of selection is from the top rows
7 B 940 928 No
98 Y 371 171 Yes
99 Y 733 364 Yes <~~~ 30 % of selection is from the bottom rows.
100 Y 546 641 No
==X==============================================================X==
Copy+Paste this part. (If on a Mac, it is already copied!)
==X==============================================================X==
DF <- structure(list(id = structure(c(1L, 1L, 1L, 1L, 2L, 2L, 2L, 25L, 25L, 25L), .Label = c("A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y"), class = "factor"), X1 = c(266L, 373L, 573L, 907L, 202L, 895L, 940L, 371L, 733L, 546L), X73 = c(960L, 315L, 208L, 850L, 46L, 969L, 928L, 171L, 364L, 641L), Class = structure(c(2L, 1L, 1L, 2L, 2L, 2L, 1L, 2L, 2L, 1L), .Label = c("No", "Yes"), class = "factor")), .Names = c("id", "X1", "X73", "Class"), class = "data.frame", row.names = c(1L, 2L, 3L, 4L, 5L, 6L, 7L, 98L, 99L, 100L))
==X==============================================================X==
Zauważ również, że całość wyniku jest w ładnej pojedynczej, długiej linii, a nie w wysokim akapicie z pociętymi wierszami. Ułatwia to czytanie postów z pytaniami SO, a także ułatwia kopiowanie i wklejanie.
Aktualizacja październik 2013:
Możesz teraz określić, ile wierszy tekstu zajmie wyjście (tj. Co wkleisz do StackOverflow). Użyj lines.out=n
argumentu do tego. Przykład:
reproduce(DF, cols=c(1:3, 17, 23), lines.out=7)
plony:
==X==============================================================X==
Copy+Paste this part. (If on a Mac, it is already copied!)
==X==============================================================X==
DF <- structure(list(id = structure(c(1L, 1L, 1L, 1L, 2L, 2L, 2L, 25L,25L, 25L), .Label
= c("A", "B", "C", "D", "E", "F", "G", "H","I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U","V", "W", "X", "Y"), class = "factor"),
X1 = c(809L, 81L, 862L,747L, 224L, 721L, 310L, 53L, 853L, 642L),
X2 = c(926L, 409L,825L, 702L, 803L, 63L, 319L, 941L, 598L, 830L),
X16 = c(447L,164L, 8L, 775L, 471L, 196L, 30L, 420L, 47L, 327L),
X22 = c(335L,164L, 503L, 407L, 662L, 139L, 111L, 721L, 340L, 178L)), .Names = c("id","X1",
"X2", "X16", "X22"), class = "data.frame", row.names = c(1L,2L, 3L, 4L, 5L, 6L, 7L, 98L, 99L, 100L))
==X==============================================================X==
Oto dobry przewodnik .
Najważniejsze jest to: po prostu upewnij się, że utworzyłeś mały fragment kodu, który możemy uruchomić, aby zobaczyć, na czym polega problem . Przydatna jest do tego funkcja dput()
, ale jeśli masz bardzo duże dane, możesz chcieć utworzyć mały przykładowy zestaw danych lub użyć tylko pierwszych 10 wierszy.
EDYTOWAĆ:
Upewnij się również, że sam zidentyfikowałeś problem. Przykładem nie powinien być cały skrypt R z komunikatem „W linii 200 jest błąd”. Jeśli używasz narzędzi do debugowania w R (uwielbiam browser()
) i Google, powinieneś być w stanie naprawdę zidentyfikować problem i odtworzyć trywialny przykład, w którym to samo poszło nie tak.
Lista mailingowa R-help zawiera przewodnik po publikowaniu, który obejmuje zarówno zadawanie pytań, jak i odpowiadanie na nie, w tym przykład generowania danych:
Przykłady: Czasami warto podać mały przykład, który ktoś może faktycznie uruchomić. Na przykład:
Jeśli mam macierz x w następujący sposób:
> x <- matrix(1:8, nrow=4, ncol=2,
dimnames=list(c("A","B","C","D"), c("x","y"))
> x
x y
A 1 5
B 2 6
C 3 7
D 4 8
>
jak mogę przekształcić go w ramkę danych z 8 wierszami i trzema kolumnami o nazwach „row”, „col” i „value”, które mają nazwy wymiarów jako wartości „row” i „col”, na przykład:
> x.df
row col value
1 A x 1
...
(na co odpowiedź może brzmieć:
> x.df <- reshape(data.frame(row=rownames(x), x), direction="long",
varying=list(colnames(x)), times=colnames(x),
v.names="value", timevar="col", idvar="row")
)
Szczególnie ważne jest słowo małe . Powinieneś dążyć do uzyskania minimalnego powtarzalnego przykładu, co oznacza, że dane i kod powinny być tak proste, jak to tylko możliwe, aby wyjaśnić problem.
EDYCJA: Ładny kod jest łatwiejszy do odczytania niż brzydki kod. Użyj przewodnika stylistycznego .
Od wersji R.2.14 (chyba) możesz przesyłać reprezentację tekstu danych bezpośrednio do read.table
:
df <- read.table(header=TRUE,
text="Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1 5.1 3.5 1.4 0.2 setosa
2 4.9 3.0 1.4 0.2 setosa
3 4.7 3.2 1.3 0.2 setosa
4 4.6 3.1 1.5 0.2 setosa
5 5.0 3.6 1.4 0.2 setosa
6 5.4 3.9 1.7 0.4 setosa
")
Czasami problem naprawdę nie jest odtwarzalny z mniejszą ilością danych, bez względu na to, jak bardzo się starasz, i nie występuje w przypadku danych syntetycznych (chociaż warto pokazać, jak utworzyłeś syntetyczne zestawy danych, które nie odtworzyły problemu, ponieważ wyklucza to pewne hipotezy).
- Konieczne może być umieszczenie danych w Internecie i podanie adresu URL.
- Jeśli danych nie można udostępnić publicznie, ale w ogóle można by je udostępnić, możesz zaoferować przesłanie ich pocztą e-mail zainteresowanym stronom (chociaż zmniejszy to liczbę osób, które będą kłopotać się pracą na tym).
- W rzeczywistości nie widziałem tego, ponieważ ludzie, którzy nie mogą ujawnić swoich danych, są wrażliwi na udostępnianie ich w jakiejkolwiek formie, ale wydaje się prawdopodobne, że w niektórych przypadkach można nadal publikować dane, jeśli byłyby wystarczająco anonimowe / zaszyfrowane / lekko uszkodzone w pewnym sensie.
Jeśli nie możesz tego zrobić, prawdopodobnie musisz zatrudnić konsultanta, aby rozwiązać problem ...
edycja : Dwa przydatne pytania SO dotyczące anonimizacji / szyfrowania:
- Jak utworzyć przykładowy zestaw danych z danych prywatnych (zastępując nazwy zmiennych i poziomy nieinformacyjnymi symbolami miejsca)?
- Mając zestaw liczb losowych wylosowanych z ciągłego rozkładu jednowymiarowego, znajdź rozkład
Dotychczasowe odpowiedzi są oczywiście świetne, jeśli chodzi o część dotyczącą odtwarzalności. Ma to na celu jedynie wyjaśnienie, że odtwarzalny przykład nie może i nie powinien być jedynym składnikiem pytania. Nie zapomnij wyjaśnić, jak chcesz, aby wyglądało i zarys Twojego problemu, a nie tylko, jak próbowałeś się tam dostać do tej pory. Kod to za mało; potrzebujesz też słów.
Oto powtarzalny przykład tego, czego należy unikać (zaczerpnięty z prawdziwego przykładu, imiona zostały zmienione, aby chronić niewinnych):
Poniżej znajdują się przykładowe dane i część funkcji, z którą mam problem.
code
code
code
code
code (40 or so lines of it)
Jak mogę to osiągnąć?
Mam bardzo łatwy i skuteczny sposób na zrobienie przykładu R, który nie został wspomniany powyżej. Najpierw możesz zdefiniować swoją strukturę. Na przykład,
mydata <- data.frame(a=character(0), b=numeric(0), c=numeric(0), d=numeric(0))
>fix(mydata)
Następnie możesz wprowadzić dane ręcznie. Jest to wydajne w przypadku mniejszych przykładów, a nie dużych.
Aby szybko utworzyć dput
dane, możesz po prostu skopiować (fragment) danych do schowka i uruchomić następujące polecenie w R:
dla danych w Excelu:
dput(read.table("clipboard",sep="\t",header=TRUE))
dla danych w pliku txt:
dput(read.table("clipboard",sep="",header=TRUE))
W sep
razie potrzeby możesz zmienić to drugie. To zadziała oczywiście tylko wtedy, gdy twoje dane znajdują się w schowku.
Wytyczne:
Twoim głównym celem podczas tworzenia pytań powinno być ułatwienie czytelnikom zrozumienia i odtworzenia problemu w ich systemach. Aby to zrobić:
- Podaj dane wejściowe
- Zapewnij oczekiwane wyniki
- Wyjaśnij zwięźle swój problem
- jeśli masz ponad 20 linii tekstu + kod, prawdopodobnie możesz wrócić i uprościć
- maksymalnie uprość swój kod, zachowując problem / błąd
To wymaga trochę pracy, ale wydaje się być uczciwym kompromisem, ponieważ prosisz innych, aby wykonali za Ciebie pracę.
Podanie danych:
Wbudowane zestawy danych
Najlepszym rozwiązaniem zdecydowanie ma polegać na wbudowanej zbiorów danych. Ułatwia to innym pracę nad Twoim problemem. Wpisz data()
po znaku zachęty R, aby zobaczyć, jakie dane są dla Ciebie dostępne. Kilka klasycznych przykładów:
iris
mtcars
ggplot2::diamonds
(pakiet zewnętrzny, ale prawie każdy go ma)
Sprawdź wbudowane zestawy danych, aby znaleźć taki, który pasuje do Twojego problemu.
Jeśli jesteś w stanie przeformułować swój problem, używając wbudowanych zestawów danych, znacznie bardziej prawdopodobne jest, że uzyskasz dobre odpowiedzi (i głosy za).
Dane wygenerowane samodzielnie
Jeśli problem jest bardzo specyficzny dla typu danych, które nie są reprezentowane w istniejących zestawach danych, podaj kod R, który generuje najmniejszy możliwy zestaw danych, w którym objawia się problem. Na przykład
set.seed(1) # important to make random data reproducible
myData <- data.frame(a=sample(letters[1:5], 20, rep=T), b=runif(20))
Teraz ktoś, kto próbuje odpowiedzieć na moje pytanie, może skopiować / wkleić te dwie linie i natychmiast rozpocząć pracę nad problemem.
dput
W ostateczności możesz użyć dput
do przekształcenia obiektu danych na kod R (np dput(myData)
.). Mówię jako „ostatnia deska ratunku”, ponieważ wyjście z programu dput
jest często dość nieporęczne, irytujące przy kopiowaniu i wklejaniu i przesłania resztę pytania.
Zapewnij oczekiwane wyniki:
Ktoś kiedyś powiedział:
Obraz oczekiwanego wyniku jest wart 1000 słów
- bardzo mądra osoba
Jeśli możesz dodać coś w rodzaju „Oczekiwano uzyskania tego wyniku”:
cyl mean.hp
1: 6 122.28571
2: 4 82.63636
3: 8 209.21429
jeśli chodzi o twoje pytanie, ludzie są znacznie bardziej skłonni do szybkiego zrozumienia, co próbujesz zrobić. Jeśli oczekiwany wynik jest duży i nieporęczny, prawdopodobnie nie zastanawiałeś się wystarczająco, jak uprościć problem (patrz dalej).
Wyjaśnij zwięźle swój problem
Najważniejsze jest, aby maksymalnie uprościć problem, zanim zadasz pytanie. Przeformułowanie problemu, aby działał z wbudowanymi zbiorami danych, bardzo w tym pomoże. Często przekonasz się również, że przechodząc przez proces upraszczania, odpowiesz na swój własny problem.
Oto kilka przykładów dobrych pytań:
- z wbudowanym zestawem danych
- z danymi wygenerowanymi przez użytkowników
W obu przypadkach problemy użytkownika prawie na pewno nie wynikają z przedstawionych przez nich prostych przykładów. Raczej wyabstrahowali naturę swojego problemu i zastosowali go do prostego zestawu danych, aby zadać swoje pytanie.
Dlaczego jeszcze jedna odpowiedź na to pytanie?
Ta odpowiedź skupia się na tym, co uważam za najlepszą praktykę: korzystaj z wbudowanych zestawów danych i dostarczaj w rezultacie tego, czego oczekujesz w minimalnej formie. Najbardziej widoczne odpowiedzi dotyczą innych aspektów. Nie spodziewam się, że ta odpowiedź stanie się widoczna; jest to tutaj wyłącznie po to, aby móc linkować do niego w komentarzach do pytań początkujących.
Powtarzalny kod jest kluczem do uzyskania pomocy. Jednak jest wielu użytkowników, którzy mogą być sceptyczni co do wklejenia nawet części swoich danych. Na przykład mogą pracować z danymi wrażliwymi lub oryginalnymi danymi zebranymi w celu wykorzystania w pracy naukowej. Z jakiegoś powodu pomyślałem, że fajnie byłoby mieć przydatną funkcję do „deformowania” moich danych przed ich publicznym wklejeniem. anonymize
Funkcji z pakietu SciencesPo
jest bardzo głupie, ale dla mnie to działa ładnie z dput
funkcji.
install.packages("SciencesPo")
dt <- data.frame(
Z = sample(LETTERS,10),
X = sample(1:10),
Y = sample(c("yes", "no"), 10, replace = TRUE)
)
> dt
Z X Y
1 D 8 no
2 T 1 yes
3 J 7 no
4 K 6 no
5 U 2 no
6 A 10 yes
7 Y 5 no
8 M 9 yes
9 X 4 yes
10 Z 3 no
Następnie anonimizuję to:
> anonymize(dt)
Z X Y
1 b2 2.5 c1
2 b6 -4.5 c2
3 b3 1.5 c1
4 b4 0.5 c1
5 b7 -3.5 c1
6 b1 4.5 c2
7 b9 -0.5 c1
8 b5 3.5 c2
9 b8 -1.5 c2
10 b10 -2.5 c1
Można również chcieć pobrać próbkę kilku zmiennych zamiast całych danych przed zastosowaniem polecenia anonimizacji i dput.
# sample two variables without replacement
> anonymize(sample.df(dt,5,vars=c("Y","X")))
Y X
1 a1 -0.4
2 a1 0.6
3 a2 -2.4
4 a1 -1.4
5 a2 3.6
Często potrzebujesz pewnych danych na przykład, jednak nie chcesz publikować dokładnych danych. Aby użyć istniejącej ramki data.frame w istniejącej bibliotece, użyj polecenia data do zaimportowania jej.
na przykład,
data(mtcars)
a następnie rozwiąż problem
names(mtcars)
your problem demostrated on the mtcars data set
Jeśli masz duży zbiór danych, którego nie można łatwo wprowadzić do skryptu za pomocą dput()
, prześlij swoje dane do wklejania i załaduj je za pomocą read.table
:
d <- read.table("http://pastebin.com/raw.php?i=m1ZJuKLH")
Zainspirowany @Henrik .
Opracowuję pakiet wakefield , aby rozwiązać tę potrzebę szybkiego udostępniania odtwarzalnych danych, czasami dput
działa dobrze w przypadku mniejszych zestawów danych, ale wiele problemów, z którymi mamy do czynienia, jest znacznie większych, udostępnianie tak dużego zestawu danych przez dput
jest niepraktyczne.
O:
wakefield pozwala użytkownikowi udostępniać minimalny kod w celu odtworzenia danych. Użytkownik ustawian
(liczbę wierszy) i określa dowolną liczbę wstępnie ustawionych funkcji zmiennych (obecnie jest ich 70), które naśladują rzeczywiste dane (takie jak płeć, wiek, dochód itp.)
Instalacja:
Obecnie (2015-06-11) wakefield jest pakietem GitHub, ale ostatecznie trafi do CRAN po napisaniu testów jednostkowych. Aby szybko zainstalować, użyj:
if (!require("pacman")) install.packages("pacman")
pacman::p_load_gh("trinker/wakefield")
Przykład:
Oto przykład:
r_data_frame(
n = 500,
id,
race,
age,
sex,
hour,
iq,
height,
died
)
To daje:
ID Race Age Sex Hour IQ Height Died
1 001 White 33 Male 00:00:00 104 74 TRUE
2 002 White 24 Male 00:00:00 78 69 FALSE
3 003 Asian 34 Female 00:00:00 113 66 TRUE
4 004 White 22 Male 00:00:00 124 73 TRUE
5 005 White 25 Female 00:00:00 95 72 TRUE
6 006 White 26 Female 00:00:00 104 69 TRUE
7 007 Black 30 Female 00:00:00 111 71 FALSE
8 008 Black 29 Female 00:00:00 100 64 TRUE
9 009 Asian 25 Male 00:30:00 106 70 FALSE
10 010 White 27 Male 00:30:00 121 68 FALSE
.. ... ... ... ... ... ... ... ...
Jeśli masz jedną lub więcej factor
zmiennych w swoich danych, które chcesz odtworzyć za pomocą dput(head(mydata))
, rozważ dodanie droplevels
do nich, tak aby poziomy czynników, które nie są obecne w zminimalizowanym zestawie danych, nie były uwzględniane w dput
wynikach, aby uczyń przykład minimalnym :
dput(droplevels(head(mydata)))
Zastanawiam się, czy plik http://old.r-fiddle.org/link może być bardzo fajnym sposobem na podzielenie się problemem. Otrzymuje unikalny identyfikator, taki jak i można by nawet pomyśleć o umieszczeniu go w SO.
Proszę nie wklejać danych wyjściowych konsoli w ten sposób:
If I have a matrix x as follows:
> x <- matrix(1:8, nrow=4, ncol=2,
dimnames=list(c("A","B","C","D"), c("x","y")))
> x
x y
A 1 5
B 2 6
C 3 7
D 4 8
>
How can I turn it into a dataframe with 8 rows, and three
columns named `row`, `col`, and `value`, which have the
dimension names as the values of `row` and `col`, like this:
> x.df
row col value
1 A x 1
...
(To which the answer might be:
> x.df <- reshape(data.frame(row=rownames(x), x), direction="long",
+ varying=list(colnames(x)), times=colnames(x),
+ v.names="value", timevar="col", idvar="row")
)
Nie możemy go bezpośrednio skopiować i wkleić.
Aby pytania i odpowiedzi były właściwie odtwarzalne, spróbuj je usunąć +
& >
przed opublikowaniem i umieść #
wyniki i komentarze w następujący sposób:
#If I have a matrix x as follows:
x <- matrix(1:8, nrow=4, ncol=2,
dimnames=list(c("A","B","C","D"), c("x","y")))
x
# x y
#A 1 5
#B 2 6
#C 3 7
#D 4 8
# How can I turn it into a dataframe with 8 rows, and three
# columns named `row`, `col`, and `value`, which have the
# dimension names as the values of `row` and `col`, like this:
#x.df
# row col value
#1 A x 1
#...
#To which the answer might be:
x.df <- reshape(data.frame(row=rownames(x), x), direction="long",
varying=list(colnames(x)), times=colnames(x),
v.names="value", timevar="col", idvar="row")
I jeszcze jedno, jeśli użyłeś jakiejś funkcji z jakiegoś pakietu, wspomnij o tej bibliotece.
Możesz to zrobić za pomocą reprex .
Jak zauważył mt1022 , „... dobrym pakietem do tworzenia minimalnego, odtwarzalnego przykładu jest „ reprex ” z tidyverse ”.
Według Tidyverse :
Celem „reprex” jest spakowanie problematycznego kodu w taki sposób, aby inni ludzie mogli go uruchomić i poczuć Twój ból.
Przykład podano na stronie internetowej tidyverse .
library(reprex)
y <- 1:4
mean(y)
reprex()
Myślę, że to najprostszy sposób na stworzenie powtarzalnego przykładu.
Poza wszystkimi powyższymi odpowiedziami, które uznałem za bardzo interesujące, czasami może być bardzo łatwe, ponieważ zostało to omówione tutaj: - JAK ZROBIĆ MINIMALNY POWTARZALNY PRZYKŁAD, ABY UZYSKAĆ POMOC Z R
Istnieje wiele sposobów na utworzenie losowego wektora Utwórz wektor liczbowy o wartości 100 z losowymi wartościami w R zaokrąglonymi do 2 miejsc po przecinku lub macierz losową w R
mydf1<- matrix(rnorm(20),nrow=20,ncol=5)
Zauważ, że czasami bardzo trudno jest udostępnić dane dane z różnych powodów, takich jak wymiar itp. Jednak wszystkie powyższe odpowiedzi są świetne i bardzo ważne do przemyślenia i wykorzystania, gdy chce się stworzyć powtarzalny przykład danych. Należy jednak pamiętać, że aby dane były tak reprezentatywne jak oryginał (w przypadku gdy PO nie może udostępniać oryginalnych danych), dobrze jest dodać pewne informacje do przykładu danych, tak jak (jeśli nazywamy dane mydf1)
class(mydf1)
# this shows the type of the data you have
dim(mydf1)
# this shows the dimension of your data
Ponadto należy znać typ, długość i atrybuty danych, którymi mogą być struktury danych
#found based on the following
typeof(mydf1), what it is.
length(mydf1), how many elements it contains.
attributes(mydf1), additional arbitrary metadata.
#If you cannot share your original data, you can str it and give an idea about the structure of your data
head(str(mydf1))
Oto kilka moich sugestii:
- Spróbuj użyć domyślnych zestawów danych R.
- Jeśli masz własny zbiór danych, dołącz go do niego
dput
, aby inni mogli Ci łatwiej pomóc - Nie używaj,
install.package()
chyba że jest to naprawdę konieczne, ludzie zrozumieją, jeśli używasz po prosturequire
lublibrary
Staraj się być zwięzły,
- Mam zbiór danych
- Postaraj się jak najprościej opisać potrzebne dane wyjściowe
- Zrób to sam, zanim zadasz pytanie
- Przesyłanie obrazu jest łatwe, więc jeśli masz, prześlij wykresy
- Uwzględnij również ewentualne błędy
Wszystko to jest częścią powtarzalnego przykładu.
Dobrym pomysłem jest użycie funkcji z testthat
pakietu, aby pokazać, czego się spodziewasz. W ten sposób inne osoby mogą zmieniać Twój kod, dopóki nie będzie działał bez błędów. Zmniejsza to ciężar tych, którzy chcieliby Ci pomóc, ponieważ oznacza to, że nie muszą dekodować Twojego opisu tekstowego. Na przykład
library(testthat)
# code defining x and y
if (y >= 10) {
expect_equal(x, 1.23)
} else {
expect_equal(x, 3.21)
}
jest jaśniejsze niż „Myślę, że x wyniósłby 1,23 dla y równej lub przekraczającej 10, a 3,21 w innym przypadku, ale nie otrzymałem żadnego wyniku”. Myślę, że nawet w tym głupim przykładzie kod jest jaśniejszy niż słowa. Użycie testthat
pozwala pomocnikowi skupić się na kodzie, co oszczędza czas i daje im pewność, że rozwiązali problem, zanim go opublikują