【问题标题】:Unite the columns of the dataframe based on the type of character they contain根据它们包含的字符类型联合数据框的列
【发布时间】:2021-10-28 08:05:49
【问题描述】:

所以我有以下关于前 NBA 球员薪水的数据框。原始数据位于 .txt 文件中,这就是为什么我的数据框如下所示:

  V1         V2         V3          V4         V5         V6
Vinnie     Del        Negro       .....      150000
Moses      Malone     .....                  75000
Kevin      Willis     ......      150000
Joe        Barry      Carrol      .....                 750000
Doc        Rivers     ....                              230000
Antoine    Carr       ......      85000
Hot        Rod        Williams    ...                   45000

这只是真实数据框的一瞥,其中包含 350 行和 7 列(非列完全为空)。我想要做的是重新排列这个数据框,以便最终只有两列,一列对应球员的名字,另一列对应他各自的薪水:

   name                 salary
Vinnie Del Negro        150000
Moses Malone            75000
Kevin Willis            150000
Joe Barry Carrol        750000
Doc Rivers              230000
Antoine Carr            85000
Hot Rod Williams        45000

也许这很简单,但我已经尝试解决它几个小时了,但我似乎无法接近。 我认为最好的方法是将所有字母单元格放入第一列,将所有数字单元格放入第二列。唯一的问题是,由于原始数据框是一个 .txt 文件,所有列都表示为 .characters()。

希望你能帮助我!

谢谢

【问题讨论】:

  • 看到“.....”而没有清楚地描述这些点所代表的含义总是很烦人。如果它们真的只是一堆时期,那么就这么说吧。您应该能够明白为什么我们需要知道其中的内容才能确定每行需要聚合多少列来生成玩家名称。
  • 它们实际上只是一堆句号,这就是我放它们的原因。

标签: r


【解决方案1】:

我们可以使用tidyr 中的unitecoalesce(假设.....NA 值)。如果这些是...,则使用mutate 步骤将其更改为NA(如下所示)

library(dplyr)
library(tidyr)
library(stringr)
library(purrr)
df1 %>%
  mutate(across(everything(),
   ~ case_when(str_detect(., "^\\.+$")|. == "" ~ NA_character_, 
           TRUE ~ as.character(.)))) %>%
  type.convert(as.is = TRUE) %>%
  unite(name, V1, V2, V3, na.rm = TRUE, sep = " ") %>%
  transmute(name, salary = invoke(coalesce, across(V4:V6)))

-输出

              name salary
1 Vinnie Del Negro 150000
2     Moses Malone  75000
3     Kevin Willis 150000
4 Joe Barry Carrol 750000
5       Doc Rivers 230000
6     Antoine Carr  85000
7 Hot Rod Williams  45000

数据

df1 <- structure(list(V1 = c("Vinnie", "Moses", "Kevin", "Joe", "Doc", 
"Antoine", "Hot"), V2 = c("Del", "Malone", "Willis", "Barry", 
"Rivers", "Carr", "Rod"), V3 = c("Negro", ".....", "......", 
"Carrol", "....", "......", "Williams"), V4 = c(".....", "", 
"150000", ".....", "", "85000", "..."), V5 = c("150000", "75000", 
"", "", "", "", ""), V6 = c("", "", "", "750000", "230000", "", 
"45000")), row.names = c(NA, -7L), class = "data.frame")

【讨论】:

  • 所以你认为他希望这些点成为名字的一部分?如果他们是真正的 NA,你不认为他会写“NA”
  • 空和非空描述中提到的OP。所以,我假设 .... 作为 NA
  • “....”不是 NA,它们只是点。空单元格也只是空的,它们不是 NA。
  • @TomasC8 好的,请检查我的更新
  • @akrun 效果很好,谢谢!
【解决方案2】:

另一种解决方案。根据要求,我将解释使用的正则表达式的部分。

通过使用unite,我得到了一个只有一列的数据框。执行unite 后的第一行是

Vinnie Del Negro ..... 150000 不适用

因此,分隔字符串是由空格分隔的点。因此,\\s 表示空格,\\.* 表示 0 个或多个点,最后一个空格 \\s

library(tidyverse)  

df <- data.frame(
  stringsAsFactors = FALSE,
                      V1 = c("Vinnie","Moses",
                             "Kevin","Joe","Doc","Antoine","Hot"),
                      V2 = c("Del","Malone",
                             "Willis","Barry","Rivers","Carr","Rod"),
                      V3 = c("Negro",".....",
                             "......","Carrol","....","......","Williams"),
                V4 = c(".....", NA, "150000", ".....", NA, "85000", "..."),
                V5 = c(150000L, 75000L, NA, NA, NA, NA, NA),
                V6 = c(NA, NA, NA, 750000L, 230000L, NA, 45000L)
      )
  
df  %>% 
  unite("name",sep=" ") %>% 
  separate(name, c("name", "salary"), sep="\\s\\.*\\s") %>% 
  mutate(salary = parse_number(salary))
#>               name salary
#> 1 Vinnie Del Negro 150000
#> 2     Moses Malone  75000
#> 3     Kevin Willis 150000
#> 4 Joe Barry Carrol 750000
#> 5       Doc Rivers 230000
#> 6     Antoine Carr  85000
#> 7 Hot Rod Williams  45000

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-12-29
    • 1970-01-01
    • 1970-01-01
    • 2022-08-15
    • 1970-01-01
    • 1970-01-01
    • 2021-05-03
    • 2019-02-02
    相关资源
    最近更新 更多