Как перекодировать несколько столбцов в таблице на основе другой таблицы [R или Python]? - PullRequest
0 голосов
/ 21 июня 2019

В моем фрейме данных есть несколько столбцов со строковыми значениями, которые я хочу перекодировать как целые числа. Существует более 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.

Ответы [ 4 ]

4 голосов
/ 21 июня 2019

Вот один путь из 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 с merge и rehsape2

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
2 голосов
/ 21 июня 2019

Еще один способ создания словаря

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
1 голос
/ 21 июня 2019

Использование 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

Это немного меняет порядок, но я думаю, что результат - то, что вы ищете.

1 голос
/ 21 июня 2019

С 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])]

ПРИМЕЧАНИЕ. Это можно масштабировать до любого числа столбцов

data

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))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...