2017-08-30 75 views
1

我有一個數據幀df,看起來像下面這樣:重塑長寬反覆行

Label    Info 
1 0-22 Records N/A 
2 0-22 Records Poland 
3 0-22 Records N/A 
4 0-22 Records active 
5 0-22 Records Hardcore 
6 0-22 Records N/A 
7 0-22 Records N/A 
8 Nuclear Blast "Oeschstr. 40 73072 Donzdorf" 
9 Nuclear Blast Germany 
10 Nuclear Blast +49 7162 9280-0 
11 Nuclear Blast active 
12 Nuclear Blast Hardcore (early), Metal and subgenres 
13 Nuclear Blast 1987 
14 Nuclear Blast "Anstalt Records, Arctic Serenades, Cannibalised Serial Killer, Deathwish Office, Epica, Gore Records, Grind Syndicate Media,         Mind Control Records, Nuclear Blast America, Nuclear Blast Brasil,         Nuclear Blast Entertainment, Radiation Records, Revolution Entertainment" 
15 Nuclear Blast Yes 

我想重塑的廣泛哪裏df看起來像:

Label   Address Country  Phone  Status  Genre  Year  Sub  Online 
1 0-22 Records N/A  Poland  N/A  active  Hardcore N/A  N/A  N/A 
2 Nuclear Blast "Oes.." Germany  +49... 
    . 
    . 

重複行的數量從7到9不等,我使用reshapereshape2,將鍵分配給「標籤」到n ovail。

編輯:dput

structure(list(label = c("0-22 Records", "0-22 Records", "0-22 Records", 
"0-22 Records", "0-22 Records", "0-22 Records", "0-22 Records", 
"Nuclear Blast", "Nuclear Blast", "Nuclear Blast", "Nuclear Blast", 
"Nuclear Blast", "Nuclear Blast", "Nuclear Blast", "Nuclear Blast", 
"Metal Blade Records", "Metal Blade Records", "Metal Blade Records", 
"Metal Blade Records", "Metal Blade Records"), info = c(" N/A ", 
"Poland", " N/A ", "active", " Hardcore ", " N/A ", "N/A", " Oeschstr. 
40\r\n73072 Donzdorf ", 
"Germany", " +49 7162 9280-0 ", "active", " Hardcore (early), Metal and 
subgenres ", " 1987 ", "\n\t\t\t\t\t\t\t\t\tAnstalt 
Records,\t\t\t\t\t\t\t\t\tArctic Serenades,\t\t\t\t\t\t\t\t\tCannibalised 
Serial Killer,\t\t\t\t\t\t\t\t\tDeathwish 
Office,\t\t\t\t\t\t\t\t\tEpica,\t\t\t\t\t\t\t\t\tGore 
Records,\t\t\t\t\t\t\t\t\tGrind Syndicate Media,\t\t\t\t\t\t\t\t\tMind 
Control Records,\t\t\t\t\t\t\t\t\tNuclear Blast 
America,\t\t\t\t\t\t\t\t\tNuclear Blast Brasil,\t\t\t\t\t\t\t\t\tNuclear 
Blast Entertainment,\t\t\t\t\t\t\t\t\tRadiation 
Records,\t\t\t\t\t\t\t\t\tRevolution Entertainment\t\t\t\t\t  ", 
"Yes", " 5737 Kanan Road #143\r\nAgoura Hills, California 91301 ", 
"United States", " N/A ", "active", " Heavy Metal, Extreme Metal " 
)), .Names = c("label", "info"), class = c("data.table", "data.frame" 
), row.names = c(NA, -20L), .internal.selfref = <pointer: 0x10200db78>) 
+2

新的列名稱(例如,「地址」,「國家」等)不會出現在數據中。需要將它們添加爲新列以確保給定行的數據在重新塑形後以正確的列結束。有沒有一種方法可以確定哪些新列名與數據中的哪些行一起使用? – eipi10

+0

它看起來像'0-22記錄'缺少'年份'信息。看看行數。 '0-22 Records'只有7行,而'Nuclear Blast'有8行。 – www

+0

是的,我認爲這是OP的觀點(見問題的最後一行)。如果不是'Label'每個級別的可變行數,解決方案將很簡單。 – eipi10

回答

1

對於寬數據幀中的新列的名稱(例如,AddressCountry等)不會出現在df。我們需要添加一列到df,該列將info映射到寬數據幀的正確列名,以確保給定行的數據在重塑後在正確的列中結束。

的挑戰是,我們需要找到方法來利用數據的規律性,以找出其中的info值表示GenreCountryYear,等等。根據您所提供的數據樣本,這裏有一些最初的想法。在下面的代碼中,case_when語句試圖將info映射到新的列名稱。爲了走出去,在case_when聲明中的語句試圖做到以下幾點:

  • 查找Country通過識別含有國名
  • 查找Status字符串(假設它只能爲「主動」或者「無效」 )
  • 查找Genre。在這裏你需要覆蓋更多的可能性。
  • 查找Year。我假定1950-2017年的範圍內有四位數字的行代表一年。必要時進行調整。
  • 查找Phone。我認爲它總是以+開頭,所以你可能需要更復雜的東西在這裏。
  • 查找Online(假設它只能是「是」或「否」,並且不會映射到不同列的行將只包含單詞「是」或「否」)
  • 查找Sub。這裏你可能需要更復雜的策略。現在我假定包含單詞「記錄」或「娛樂」的行或具有三個或更多逗號的行爲Sub行。
  • 如果一行不符合上述任何一條語句,則假定它是一個地址。

你需要玩弄這些,看看在你的數據上下文有什麼作用。

library(stringr) 
library(tidyverse) 
library(countrycode) 
data("countrycode_data") 

df %>% 
    filter(!grepl("N/A", info)) %>% 
    mutate(info = str_trim(gsub("\r*\t*|\n*| {2,}", "", info)), 
     NewCols = case_when(sapply(info, function(x) any(grepl(x, countrycode_data$country.name.en))) ~ "Country", 
          grepl("active", info) ~ "Status",               
          grepl("hardcore|metal|rock|classical", info, ignore.case=TRUE) ~ "Genre", 
          info %in% 1950:2017 ~ "Year", 
          grepl("^\\+", info) ~ "Phone", 
          grepl("^Yes$|^No$", info) ~ "Online", 
          grepl("Records|Entertainment|,{3,}", info) ~ "Sub", 
          TRUE ~ "Address")) %>% 
    group_by(label) %>% 
    spread(NewCols, info) 

下面是輸出(在那裏我已經被截斷的Sub長期價值,以節省空間):

   label           Address  Country         Genre Online   Phone Status   Sub Year 
       <chr>            <chr>   <chr>         <chr> <chr>   <chr> <chr>   <chr> <chr> 
1  0-22 Records            <NA>  Poland        Hardcore <NA>   <NA> active    NA <NA> 
2 Metal Blade Records 5737 Kanan Road #143Agoura Hills, California 91301 United States   Heavy Metal, Extreme Metal <NA>   <NA> active    NA <NA> 
3  Nuclear Blast       Oeschstr. 4073072 Donzdorf  Germany Hardcore (early), Metal and subgenres Yes +49 7162 9280-0 active Anstalt Re... 1987 

原來的答覆(之前的數據樣本可用)

如果您每個Label都有9行,並且每行中的數據類型總是按照每個Label的順序排列,那麼一種解決方案是:

library(tidyverse) 

df.wide = df %>% 
    group_by(Label) %>% 
    mutate(NewCols = rep(c("Address","Country","Phone","Status","Genre","Year","Sub","Online"), length(unique(Label)))) %>% 
    spread(NewCols, Info) 

您可以在具有9行的Label的任何級別的實際數據中實現此功能。

df.wide9 = df %>% 
    group_by(Label) %>% 
    filter(n()==9) %>% 
    mutate(NewCols = rep(c("Address","Country","Phone","Status","Genre","Year","Sub","Online"), length(unique(Label)))) %>% 
    spread(NewCols, Info) 

對於Label具有8個或7行中的水平,如果丟失的行始終代表相同的類型的數據,例如,說的地址行是一個總是缺少的8行水平Label,那麼你可以做(​​再次,假設數據的數據類型都以相同的順序爲每個Label):

df.wide8 = df %>% 
    group_by(Label) %>% 
    filter(n()==8) %>% 
    mutate(NewCols = rep(c("Country","Phone","Status","Genre","Year","Sub","Online"), length(unique(Label)))) %>% 
    spread(NewCols, Info) 

然後,你可以把它們與df.wide = bind_rows(df.wide8, df.wide9)在一起。

如果您提供了更多信息,我們可能會想出適用於您的實際數據的解決方案。

+0

謝謝,但不幸的是,這些工作都不是由於'mutate_impl(.data,dots)中的錯誤的變化造成的: Column NewCols必須是長度9(組大小)或者一個而不是8或7。 – torentino