2012-04-15 6 views
7

Mam zestaw ramek danych z tymi samymi nagłówkami kolumn, z tym że niektóre nazwy kolumn są pisane dużymi literami, a niektóre małymi literami. Chcę przekonwertować wszystkie nazwy kolumn na małe litery, aby utworzyć jedną dużą ramkę danych.Jak ustawić nazwy kolumn na małe litery dla wielu ramek danych?

Nie mogę sprawić, by colnames() zadziałał w dowolnej pętli lub zastosowałem opcję Pisanie. Z:

#create dfs 
df1<-data.frame("A" = 1:10, "B" = 2:11) 
df2<-data.frame("a" = 3:12, "b" = 4:13) 
df3<-data.frame("a" = 5:14, "b" = 6:15) 
#I have many more dfs in my actual data 

#make list of dfs, define lowercasing function, apply across df list 
dfs<-ls(pattern = "df") 
lowercols<-function(df){colnames(get(df))<-tolower(colnames(get(df)))} 
lapply(dfs, lowercols) 

pojawia się następujący błąd:

Error in colnames(get(df)) <- tolower(colnames(get(df))) : 
    could not find function "get<-" 

Jak zmienić wszystkie moje dataframes mieć małe nazwy kolumn?

Odpowiedz

8

Poniższa powinno działać:

dfList <- lapply(lapply(dfs,get),function(x) {colnames(x) <- tolower(colnames(x));x}) 

Problemy takie jak ten na ogół wynikają z faktu, że nie zostały umieszczone wszystkie ramki danych w pojedynczej strukturze danych, a następnie są zmuszeni do korzystania coś niewygodne, jak get.

Nie, że w moim kodu używam lapply i get faktycznie stworzyć jedną listę ramek danych pierwszych, a następnie zmienić ich colnames.

Należy również pamiętać, że funkcja lowcols ma raczej charakter nie-R. Funkcje R na ogół nie są wywoływane w taki sposób, że nic nie zwracają, ale mają efekty uboczne. Jeśli spróbujesz napisać funkcje w ten sposób (co jest możliwe) prawdopodobnie utrudnisz sobie życie i będziesz mieć problemy z zakresu. Zauważ, że w moim drugim lapply jawnie zwracam zmodyfikowaną ramkę danych.

+0

Dlaczego nie zdarzyło mi się samodzielnie sporządzić listy ramek danych? Oczywiście to lepsze rozwiązanie. Przyjmuję odpowiedź, gdy tylko będę miał szansę wypróbować. –

+0

To działa idealnie, a następnie mając ramki danych jako listę, uzyskanie wszystkich oddzielnych ramek danych w jeden duży plik df było tak proste, jak 'dane <-danie (dfList, rbind.fill). Dzięki i jestem bardzo wdzięczny tutaj konstruktywna i pomocna społeczność. –

+0

Czy 'lapply (dfs, get)' naprawdę jest konieczne? Po prostu dostarczenie listy data.frames nie wystarczy? –

4

@ joran odpowiedź nakłada się na mnie mocno, zarówno w stylu, jak i "prawdopodobnie chcesz to zrobić inaczej". Jednak w duchu "dajcie człowiekowi rybę, a karmicie go na jeden dzień, dajcie mu ostry kij, a on może szturchnąć się w oczy" ...

Oto funkcja, która robi to, co chcesz w taki sposób, że (uważasz) chcesz zrobić:

dfnames <- ls(pattern = "df[0-9]+") ## avoid 'dfnames' itself 
lowercolnames <- function(df) { 
    x <- get(df) 
    colnames(x) <- tolower(colnames(x)) 
    ## normally I would use parent.frame(), but here we 
    ## have to go back TWO frames if this is used within lapply() 
    assign(df,x,sys.frame(-2)) 
    ## OR (maybe simpler) 
    ## assign(df,x,envir=.GlobalEnv) 

    NULL 
} 

Oto dwa alternatywne funkcje małe nazwy kolumn i zwraca wynik:

lowerCN2 <- function(x) { 
    colnames(x) <- tolower(colnames(x)) 
    x 
} 

i obejmują plyr::rename tutaj dla kompletności, choć w tym przypadku jest to więcej kłopotów niż jest warte.

lowerCN3 <- function(x) { 
    plyr::rename(x,structure(tolower(colnames(x)), 
          names=colnames(x))) 
} 

dflist <- lapply(dfnames,get) 
dflist <- lapply(dflist,lowerCN2) 
dflist <- lapply(dflist,lowerCN3) 
+0

+1 za dawanie człowiekowi ostrego kija. –

+0

Dzięki za jasny kod pokazujący, jak zrobiłbym to, co myślałem, że chcę zrobić. Nie rozumiem, co robi 'sys.frame (-2)' w 'assign()', ale to pewnie dlatego, że nie rozumiem, aby to wszystko przypisać. –

1

To nie odpowiada bezpośrednio na twoje pytanie, ale może rozwiązać problem, który próbujesz rozwiązać; możesz połączyć dane.frame pod różnymi nazwami przez coś takiego:

df1 <- data.frame("A" = 1:10, "B" = 2:11, x=letters[1:10]) 
df2 <- data.frame("a" = 3:12, "b" = 4:13, y=LETTERS[1:10]) 
merge(df1, df2, by.x=c("A","B"), by.y=c("a","b"), all=TRUE) 
+0

Mając do czynienia z więcej niż 2 plikami df, scalanie nie jest odpowiedzią, ale dzięki za wskazówki. Jestem pewna, że ​​przydadzą się w przyszłości. –

+0

@WilliamGunn: Powiedziałeś: "Chcę przekonwertować wszystkie nazwy kolumn na małe litery, aby móc je scalić." Właśnie wskazywałem, że nie trzeba zmieniać nazw kolumn, aby scalić dane.frame. Być może użyłeś scalania, kiedy miałeś na myśli append/rbind? –

+0

Zrozumiałem, co odpowiadasz i dzięki! To było mylące, jak użyłem słowa "merge", ale nie oznaczało to użycia 'merge()', które działa tylko na parach ramek danych. Zmienię to. –