【问题标题】:How to recode multiple columns in a table based on another table [R or Python]?如何根据另一个表 [R 或 Python] 重新编码表中的多个列?
【发布时间】:2019-11-04 13:18:04
【问题描述】:

我的数据框有几列带有字符串值,我想将它们重新编码为整数。 有超过 20 列,每列都有其唯一的键值对(并且并非所有都必须重新编码),所以我正在寻找一种方法来避免写 20 + case_when's,每个案例有 3-6 个案例(这是我迄今为止阅读的 3+ 个答案所建议的)。

我在不同的表中有字符串-整数对,我想知道是否有一种方法可以遍历数据列和键值对的行,以重新编码字符串,如下所示:

数据:

C1 C2 C3
A  D  X
B  E  Y
C  F  Z

键值对:

Column_name  String   Int
C2           D        5
C2           E        10
C2           F        0
C3           X        1
C3           Y        2
C3           Z        7   

输出:

C1  C2  C3
A   5   1
B   10  2
C   0   7

换句话说,对于每个数据列 C#,代码将只查看 C# 的键值行,并将字符串替换为其值。

我愿意接受 R 或 Python 解决方案。

【问题讨论】:

    标签: python r pandas dplyr


    【解决方案1】:

    这是pandas的一种方式

    d={x : y.set_index('String').Int.to_dict() for x , y in pairs.groupby('Column_name')}
    Data.replace(d)
    Out[611]: 
      C1  C2  C3
    0  A   5   1
    1  B  10   2
    2  C   0   7
    

    在 R 中,mergerehsape2

    df1$id=1:dim(df1)[1]
    s=merge(melt(df1,'id'),pairs,by.x=c('variable','value'),by.y=c('Column_name','String'),all.x=T)
    s$Int[is.na(s$Int)]=s$value[is.na(s$Int)]
    
    dcast(data = s, formula = id ~ variable, value.var = "Int")
      id C1 C2 C3
    1  1  A  5  1
    2  2  B 10  2
    3  3  C  0  7
    

    【讨论】:

    • 'String' 中的值可能在不同的'Column_name' 组中重复。使用这个df.replace({k: dict(zip(d.String, d.Int)) for k, d in pairs.groupby('Column_name')})
    • @piRSquared 是的,请注意这一点,然后更新:-),谢谢先生
    • 这太快了——而且是两种语言!您,先生或女士,简直让我大吃一惊——太棒了。
    • @Khashir yw :-) 快乐编码
    【解决方案2】:

    另一种创建字典的方法

    d = {}
    for c, s, i in zip(*map(pairs.get, pairs)):
        d.setdefault(c, {})[s] = i
    
    df.replace(d)
    
      C1  C2  C3
    0  A   5   1
    1  B  10   2
    2  C   0   7
    

    【讨论】:

    • 哇,这么简洁。这是否会扩展到任意数量的列,而不是所有列都必须重新编码?
    • 会的。它告诉replace 只替换字典指定的列。请注意,WeNYoBen 的回答也是如此。
    【解决方案3】:

    有了R,我们可以在没有任何包的情况下(在base R中)使用命名向量来做到这一点

    df1[-1] <- Map(function(x, y) y[x], df1[-1], 
              with(df2, split(setNames(Int, String), Column_name)))
    
    df1
    #  C1 C2 C3
    #1  A  5  1
    #2  B 10  2
    #3  C  0  7
    

    另外,如果列是有序的,那么这会更紧凑

    df1[-1] <-  with(df2, setNames(Int, String))[as.matrix(df1[-1])]
    

    并且没有任何空格(#save_space)

    df1[-1]<-with(df2,setNames(Int,String))[as.matrix(df1[-1])]
    

    注意:这可以扩展到任意数量的列

    数据

    df1 <- structure(list(C1 = c("A", "B", "C"), C2 = c("D", "E", "F"), 
        C3 = c("X", "Y", "Z")), class = "data.frame", row.names = c(NA, 
    -3L))
    
    df2 <- structure(list(Column_name = c("C2", "C2", "C2", "C3", "C3", 
    "C3"), String = c("D", "E", "F", "X", "Y", "Z"), Int = c(5L, 
    10L, 0L, 1L, 2L, 7L)), class = "data.frame", row.names = c(NA, 
    -6L))
    

    【讨论】:

      【解决方案4】:

      使用 dplyr left_join:

      library(dplyr)
      library(tidyr)
      
      
      data %>% 
          gather(Column_name, String, -C1) %>% 
          left_join(key_vals) %>% 
          select(-String) %>% 
          spread(Column_name, Int)
      
      #### OUTPUT ####
      
        C1 C2 C3
      1  A  5  1
      2  B 10  2
      3  C  0  7
      

      可以通过从gather 中排除更多变量来扩展此方法。例如,使用以下数据框:

      data <- bind_cols(data, data)
      
      #### OUTPUT ####
      
        C1 C2 C3 C11 C21 C31
      1  A  D  X   A   D   X
      2  B  E  Y   B   E   Y
      3  C  F  Z   C   F   Z
      

      如果我们不想重新编码 C11-C31,我们可以从 gather 中减去它们。您还需要在 left_join 中指定要加入的变量(上面没有必要,因为它们是唯一的可能性):

      
      data %>% 
          gather(Column_name, String, -c(C1, C11:C31)) %>% 
          left_join(key_vals, by = c("Column_name", "String")) %>% 
          select(-String) %>% 
          spread(Column_name, Int)
      
      #### OUTPUT ####
      
        C1 C11 C21 C31 C2 C3
      1  A   A   D   X  5  1
      2  B   B   E   Y 10  2
      3  C   C   F   Z  0  7
      

      它稍微改变了顺序,但我认为结果就是你想要的。

      【讨论】:

      • 这种方法是否可以扩展到任意数量的列,而不是所有列都必须重新编码?
      • @Khashir 是的,我相信如果你在最初的gather 中包含这些列。
      • @Khashir 我在我的答案中添加了一个示例,其中一些变量没有被重新编码。
      • 没有一个解决方案是开箱即用的(可能是实际数据的问题);但是这个逻辑帮助我找到了解决方案。因此,我选择了这个作为答案。
      猜你喜欢
      • 1970-01-01
      • 2022-11-28
      • 1970-01-01
      • 2011-11-25
      • 1970-01-01
      • 1970-01-01
      • 2019-07-09
      • 2016-02-19
      • 1970-01-01
      相关资源
      最近更新 更多