Подтвердить что ты не робот

Заменить строку/значение во всем DataFrame

У меня очень большой набор данных, я хочу заменить строки номерами. Я хотел бы работать с набором данных без ввода функции отображения для каждого ключа (столбца) в наборе данных. (аналогично методу fillna, но заменяет конкретную строку ассоциированным значением). Есть ли способ сделать это?

Вот пример моего набора данных

data
   resp          A          B          C
0     1       poor       poor       good
1     2       good       poor       good
2     3  very good  very good  very good
3     4       bad        poor       bad 
4     5   very bad   very bad   very bad
5     6       poor       good   very bad
6     7       good       good       good
7     8  very good  very good  very good
8     9       bad        bad    very bad
9    10   very bad   very bad   very bad

Желаемый результат:

 data
   resp  A  B  C
0      1  3  3  4
1     2  4  3  4
2     3  5  5  5
3     4  2  3  2
4     5  1  1  1
5     6  3  4  1
6     7  4  4  4
7     8  5  5  5
8     9  2  2  1
9    10  1  1  1

very bad = 1, bad = 2, poor = 3, good = 4, very good = 5

//Jonas

4b9b3361

Ответ 1

Используйте replace

In [126]: df.replace(['very bad', 'bad', 'poor', 'good', 'very good'], 
                     [1, 2, 3, 4, 5]) 
Out[126]: 
      resp  A  B  C
   0     1  3  3  4
   1     2  4  3  4
   2     3  5  5  5
   3     4  2  3  2
   4     5  1  1  1
   5     6  3  4  1
   6     7  4  4  4
   7     8  5  5  5
   8     9  2  2  1
   9    10  1  1  1

Ответ 2

Учитывая, что data является вашим pandas DataFrame, вы также можете использовать:

data.replace({'very bad': 1, 'bad': 2, 'poor': 3, 'good': 4, 'very good': 5}, inplace=True)

Ответ 3

v0. 23+ Ответ,...
Включает в себя некоторые альтернативы производительности, в том числе использование pd.Categorical.


DataFrame.replace
Если замена должна быть выполнена для подмножества столбцов, то не следует вызывать replace для всего DataFrame. Например, вы можете нарезать с помощью DataFrame.loc и вызывать replace с помощью dict mapping.

df    

   resp          A          B          C
0     1       poor       poor       good
1     2       good       poor       good
2     3  very good  very good  very good
3     4        bad       poor        bad
4     5   very bad   very bad   very bad

mapping = {'very bad': 1, 'bad': 2, 'poor': 3, 'good': 4, 'very good': 5}

df.loc[:,'A':'C'] = df.loc[:,'A':'C'].replace(mapping)
df

   resp  A  B  C
0     1  3  3  4
1     2  4  3  4
2     3  5  5  5
3     4  2  3  2
4     5  1  1  1

Если вам нужно выполнить замену регулярного выражения, добавьте флаг regex=True:

df.loc[:,'A':'C'].replace({'bad': 'x', 'good': 'y'}, regex=True)

        A       B       C
0    poor    poor       y
1       y    poor       y
2  very y  very y  very y
3       x    poor       x
4  very x  very x  very x

Если вы не хотите изменять оригинал, используйте DataFrame.join чтобы вернуть "resp" в копию:

result = df[['resp']].join(df.loc[:,'A':'C'].replace(mapping))
result

   resp  A  B  C
0     1  3  3  4
1     2  4  3  4
2     3  5  5  5
3     4  2  3  2
4     5  1  1  1

Series.map с помощью DataFrame.apply
Вы также можете apply Series.map -based к каждому столбцу. map как правило, быстрее, чем replace в серии, но ваш пробег может отличаться.

df.loc[:,'A':'C'].apply(lambda x: x.map(mapping))

   resp  A  B  C
0     1  3  3  4
1     2  4  3  4
2     3  5  5  5
3     4  2  3  2
4     5  1  1  1

Обратите внимание, что отсутствующие отображения из Серии заменяются на NaN.

df.loc[:,'A':'C'].apply(lambda x: x.map({'poor': '3'}))

     A    B    C
0    3    3  NaN
1  NaN    3  NaN
2  NaN  NaN  NaN
3  NaN    3  NaN
4  NaN  NaN  NaN

pd.Categorical
Это еще одна полезная опция и довольно быстрая. Вы можете создавать категории с указанным порядком, и позволить пандам назначать коды для вас.

labels = ['very bad', 'bad', 'poor', 'good', 'very good']
df.loc[:,'A':'C'].apply(
    lambda x: pd.Categorical(x, categories=labels, ordered=True).codes + 1)

   A  B  C
0  3  3  4
1  4  3  4
2  5  5  5
3  2  3  2
4  1  1  1

df[['resp']].join(df.loc[:,'A':'C'].apply(
     lambda x: pd.Categorical(x, categories=labels, ordered=True).codes + 1)
)

   resp  A  B  C
0     1  3  3  4
1     2  4  3  4
2     3  5  5  5
3     4  2  3  2
4     5  1  1  1

Спектакль
В наших тестах мы не будем заботиться о том, чтобы вернуть результат в ответ. Это будет стремиться вовремя только заменить.

Функции были рассчитаны по perfplot модуля perfplot.

enter image description here

Код бенчмаркинга

import perfplot 
import pandas as pd

data = {
 'A': ['poor', 'good', 'very good', 'bad' , 'very bad'],
 'B': ['poor', 'poor', 'very good', 'poor', 'very bad'],
 'C': ['good', 'good', 'very good', 'bad' , 'very bad']
} 

df = pd.DataFrame(data)

perfplot.show(
    setup=lambda n: pd.concat([df] * n, ignore_index=True),
    kernels=[
        lambda df: df.replace(mapping),
        lambda df: df.apply(lambda x: x.map(mapping)),
        lambda df: df.apply(
            lambda x: pd.Categorical(x, categories=labels, ordered=True).codes + 1)
    ],
    labels=['replace', 'apply + map', 'apply + pd.Categorical'],
    n_range=[2**k for k in range(0, 10)],
    xlabel='N',
    logy=True
)

Это только проверяет функции на фреймах данных, которые увеличивают глубину, а не ширину. В зависимости от количества строк и столбцов ваш пробег может варьироваться, поэтому лучше всего протестировать каждый метод в вашем DataFrame и использовать то, что работает лучше всего.