Tengo varios marcos de datos de pandas que pueden tener un número diferente de columnas y el número de estas columnas generalmente varía de 50 a 100. Necesito crear una columna final que sea simplemente todas las columnas concatenadas. Básicamente, la cadena en la primera fila de la columna debe ser la suma (concatenación) de las cadenas en la primera fila de todas las columnas. Escribí el ciclo a continuación, pero creo que podría haber una forma mejor y más eficiente de hacerlo. Alguna idea sobre cómo hacer esto
num_columns = df.columns.shape[0] col_names = df.columns.values.tolist() df.loc[:, 'merged'] = "" for each_col_ind in range(num_columns): print('Concatenating', col_names[each_col_ind]) df.loc[:, 'merged'] = df.loc[:, 'merged'] + df[col_names[each_col_ind]]Solución con sum , pero la salida es float , por lo que es necesario convertir a int y str :
df['new'] = df.sum(axis=1).astype(int).astype(str) Otra solución con la función apply join , pero es la más lenta:
df['new'] = df.apply(''.join, axis=1) Última numpy solution muy rápida: convertir a numpy array y luego 'sumar' :
df['new'] = df.values.sum(axis=1)Horarios :
df = pd.DataFrame({'A': ['1', '2', '3'], 'B': ['4', '5', '6'], 'C': ['7', '8', '9']}) #[30000 rows x 3 columns] df = pd.concat([df]*10000).reset_index(drop=True) #print (df) cols = list('ABC') #not_a_robot solution In [259]: %timeit df['concat'] = pd.Series(df[cols].fillna('').values.tolist()).str.join('') 100 loops, best of 3: 17.4 ms per loop In [260]: %timeit df['new'] = df[cols].astype(str).apply(''.join, axis=1) 1 loop, best of 3: 386 ms per loop In [261]: %timeit df['new1'] = df[cols].values.sum(axis=1) 100 loops, best of 3: 6.5 ms per loop In [262]: %timeit df['new2'] = df[cols].astype(str).sum(axis=1).astype(int).astype(str) 10 loops, best of 3: 68.6 ms per loop EDITAR Si los dtypes de algunas columnas no son object (obviamente string s) emitidos por DataFrame.astype :
df['new'] = df.astype(str).values.sum(axis=1)df = pd.DataFrame({'A': ['1', '2', '3'], 'B': ['4', '5', '6'], 'C': ['7', '8', '9']}) df['concat'] = pd.Series(df.fillna('').values.tolist()).str.join('')Nos da:
df Out[6]: ABC concat 0 1 4 7 147 1 2 5 8 258 2 3 6 9 369Para seleccionar un conjunto dado de columnas:
df['concat'] = pd.Series(df[['A', 'B']].fillna('').values.tolist()).str.join('') df Out[8]: ABC concat 0 1 4 7 14 1 2 5 8 25 2 3 6 9 36 Sin embargo, he notado que ese enfoque a veces puede resultar en que NaN se complete donde no debería, así que aquí hay otra forma:
>>> from functools import reduce >>> df['concat'] = df[cols].apply(lambda x: reduce(lambda a, b: a + b, x), axis=1) >>> df ABC concat 0 1 4 7 147 1 2 5 8 258 2 3 6 9 369Aunque cabe señalar que este enfoque es mucho más lento:
$ python3 -m timeit 'import pandas as pd;from functools import reduce; df=pd.DataFrame({"a": ["this", "is", "a", "string"] * 5000, "b": ["this", "is", "a", "string"] * 5000});[df[["a", "b"]].apply(lambda x: reduce(lambda a, b: a + b, x)) for _ in range(10)]' 10 loops, best of 3: 451 msec per loopVersus
$ python3 -m timeit 'import pandas as pd;from functools import reduce; df=pd.DataFrame({"a": ["this", "is", "a", "string"] * 5000, "b": ["this", "is", "a", "string"] * 5000});[pd.Series(df[["a", "b"]].fillna("").values.tolist()).str.join(" ") for _ in range(10)]' 10 loops, best of 3: 98.5 msec per loopNo tengo suficiente reputación para comentar, así que estoy construyendo mi respuesta a partir de la respuesta de Blacksite.
Para mayor claridad, LunchBox comentó que falló para Python 3.7.0. También me falló en Python 3.6.3. Aquí está la respuesta original de blacksite:
df['concat'] = pd.Series(df.fillna('').values.tolist()).str.join('')Aquí está mi modificación para Python 3.6.3:
df['concat'] = pd.Series(df.fillna('').values.tolist()).map(lambda x: ''.join(map(str,x)))