Tengo un gran conjunto de datos (300 millones de filas) y necesito un algoritmo eficiente (o rápido) que haga el trabajo. Así que aquí hay algunas filas de conjuntos de datos.

db = pd.DataFrame({'A': [2,3,4,5], 'T': [1,2,6,7], 'G': [8, 1, 4, 6], 
                 'C': [1,1 , 3, 4], 'basecall' : ['G', 'A', 'G', 'T']})

Necesito una nueva columna (max_eliminate) y se calcula eliminando el valor correspondiente en la columna basecall y luego encuentra el máximo para el resto de los tres valores. Entonces, para la fila uno, basecall es "G" y después de eliminar el valor correspondiente, que es 8 y los tres valores restantes son 2, 1, 1. La columna max_eliminate seleccionará el máximo de estos valores, que es 2 para esta fila.

db_new = pd.DataFrame({'A': [2,3,4,5], 'T': [1,2,6,7], 'G': [8, 1, 4, 6], 
                       'C': [1,1 , 3, 4], 'basecall' : ['G', 'A', 'G', 'T'], 
                       'max_eliminate' : [2, 2, 6, 6]})

Leeré este conjunto de datos por trozos de 1 millón de filas a la vez

3
kelvinfrog 26 ago. 2020 a las 19:29

2 respuestas

La mejor respuesta

stack luego filtre las filas donde 'basecall' es el mismo que el encabezado de columna original. Luego agg con max sobre el índice original.

s = db.set_index('basecall', append=True).stack()
db['max_eliminate'] = (s[s.index.get_level_values('basecall') != s.index.get_level_values(-1)]
                          .groupby(level=0).max())

   A  T  G  C basecall  max_eliminate
0  2  1  8  1        G              2
1  3  2  1  1        A              2
2  4  6  4  3        G              6
3  5  7  6  4        T              6

Otro enfoque de numpy es usar la transmisión para crear la máscara para las columnas de DataFrame (que no sean 'basecall'), luego max a lo largo de las filas, ya que ignora NaN

m = db.columns[:-1].to_numpy() == db['basecall'].to_numpy()[:, None]
#[[False False  True False]
# [ True False False False]
# [False False  True False]
# [False  True False False]]

db['max_eliminate'] = db.drop(columns='basecall').mask(m).max(1)
3
ALollz 26 ago. 2020 a las 17:54

Utilice DataFrame.lookup para buscar los valores basados en columnas en db['basecall'], luego use DataFrame.filter para seleccionar las columnas excepto basecall y usar DataFrame.mask para enmascarar los valores de búsqueda, es decir, s, finalmente use DataFrame.max a lo largo de axis=1:

s = db.lookup(db.index, db['basecall'])
db['max_eliminate'] = db.filter(regex='^(?!basecall)')\
                        .mask(lambda x: x.eq(s, axis=0)).max(1)

Resultado:

   A  T  G  C basecall  max_eliminate
0  2  1  8  1        G            2.0
1  3  2  1  1        A            2.0
2  4  6  4  3        G            6.0
3  5  7  6  4        T            6.0
4
Shubham Sharma 26 ago. 2020 a las 16:54