Mam ramkę danych i dla każdego wiersza w tej ramce muszę wykonać skomplikowane wyszukiwania i dołączyć niektóre dane do pliku.
DataFrame zawiera wyniki naukowe dla wybranych dołków z 96-dołkowych płytek używanych w badaniach biologicznych, więc chcę zrobić coś takiego:
for (well in dataFrame) {
wellName <- well$name # string like "H1"
plateName <- well$plate # string like "plate67"
wellID <- getWellID(wellName, plateName)
cat(paste(wellID, well$value1, well$value2, sep=","), file=outputFile)
}
W moim świecie proceduralnym zrobiłbym coś takiego:
for (row in dataFrame) {
#look up stuff using data from the row
#write stuff to the file
}
Jaki jest „sposób R”, aby to zrobić?
Odpowiedzi:
Możesz tego spróbować, używając
apply()
funkcjiźródło
x
), jest wektorem. Dlatego powyższy przykład musi używać indeksów numerycznych; podejście by () daje data.frame, dzięki czemu kod jest bardziej niezawodny.wellName <- x[1]
mogłoby też byćwellName <- x["name"]
.Możesz użyć
by()
funkcji:Ale bezpośrednie iterowanie po wierszach rzadko jest tym, czego chcesz; zamiast tego powinieneś spróbować wektoryzować. Czy mogę zapytać, co właściwie robi w pętli?
źródło
1:0
nie jest pustaseq_len(nrow(dataFrame))
zamiast1:nrow(dataFrame)
.dostuff
tę odpowiedź nastr(row)
Zobaczysz w konsoli wydrukowanych wiele wierszy zaczynających się od „'data.frame': 1 obs z x zmiennych.” Ale bądź ostrożny, zmianadostuff
narow
nie zwraca obiektu data.frame dla funkcji zewnętrznej jako całości. Zamiast tego zwraca listę jednowierszowych ramek danych.Po pierwsze, poprawna jest uwaga Jonathana dotycząca wektoryzacji. Jeśli funkcja getWellID () jest wektoryzowana, możesz pominąć pętlę i po prostu użyć cat lub write.csv:
Jeśli getWellID () nie jest wektoryzowane, wtedy zalecenie Jonathana dotyczące użycia
by
lub sugestia knguyenapply
powinna zadziałać.W przeciwnym razie, jeśli naprawdę chcesz użyć
for
, możesz zrobić coś takiego:Możesz także spróbować użyć
foreach
pakietu, chociaż wymaga to zaznajomienia się z tą składnią. Oto prosty przykład:Ostatnią opcją jest użycie funkcji poza
plyr
pakietem, w którym to przypadku konwencja będzie bardzo podobna do funkcji stosującej.źródło
mapply(getWellId, well$name, well$plate)
.foreach
- wykorzystam to do diabła.Myślę, że najlepszym sposobem na zrobienie tego z podstawowym R jest:
Przewaga nad
for( i in 1:nrow(df))
podejściem polega na tym, że nie wpadasz w kłopoty, jeślidf
jest pusty inrow(df)=0
.źródło
Używam tej prostej funkcji narzędzia:
Lub szybsza, mniej przejrzysta forma:
Ta funkcja po prostu dzieli plik data.frame na listę wierszy. Następnie możesz ustawić normalne „dla” na tej liście:
Twój kod z pytania będzie działał z minimalną modyfikacją:
źródło
lapply
iteruje po kolumnach całego zbioru danychx
, nadając każdej kolumnie nazwęc
, a następnie wyodrębniająci
th wpis z tego wektora kolumnowego. Czy to jest poprawne?wellName <- as.character(well$name)
.Byłem ciekawy wydajności czasowej opcji niewektoryzowanych. W tym celu użyłem funkcji f zdefiniowanej przez knguyen
i ramkę danych, taką jak ta w jego przykładzie:
Dodałem dwie wektoryzowane funkcje (na pewno szybciej niż inne), aby porównać podejście cat () z metodą write.table () ...
Wynikowy obraz pokazuje, że Apply zapewnia najlepszą wydajność dla wersji niewektoryzowanej, podczas gdy write.table () wydaje się działać lepiej niż cat ().
źródło
Możesz użyć do tego
by_row
funkcji z pakietupurrrlyr
:Domyślnie zwracana wartość z
myfn
jest umieszczana w nowej kolumnie listy w nazwie df.out
.Jeśli jest to jedyne pożądane wyjście, możesz napisać
purrrlyr::by_row(df, myfn)$.out
źródło
Cóż, ponieważ poprosiłeś o odpowiednik R w innych językach, próbowałem to zrobić. Wydaje się, że działa, chociaż tak naprawdę nie sprawdziłem, która technika jest bardziej wydajna w R.
Jednak w przypadku kolumn kategorycznych pobierze ramkę danych, którą w razie potrzeby możesz przesłać na maszynie za pomocą as.character ().
źródło