Procesamiento de datos con la adición de columnas dinámicamente en Python Pandas Dataframe

Tengo el siguiente problema. Digamos que este es mi CSV

id f1 f2 f3 1 4 5 5 1 3 1 0 1 7 4 4 1 4 3 1 1 1 4 6 2 2 6 0 .......... 

Por lo tanto, tengo filas que se pueden agrupar por ID. Quiero crear un csv como abajo como una salida.

 f1 f2 f3 f1_n f2_n f3_n f1_n_n f2_n_n f3_n_n f1_t f2_t f3_t 4 5 5 3 1 0 7 4 4 1 4 6 

Por lo tanto, quiero poder elegir el número de filas que agarraré para convertirlas en columnas (siempre comenzando desde la primera fila de una identificación). En este caso agarré 3 filas. También omitiré una o más filas (en este caso, solo una omisión) para tomar las columnas finales de la última fila del mismo grupo de ID. Y por razones, quiero usar un dataframe.

Después de luchar por unas 3-4 horas. Descubrí una solución como se indica a continuación. Pero mi solución es muy lenta. Tengo alrededor de 700,000 filas y puede haber alrededor de 70,000 grupos de identificaciones. El código anterior en el modelo = 3 toma casi una hora en mi 4GB 4 Core Lenovo. Necesito ir al modelo = quizás 10 o 15. Todavía soy un principiante en Python y estoy seguro de que puede haber varios cambios que lo harán rápido. ¿Puede alguien explicar profundamente cómo puedo mejorar el código?

Gracias una tonelada.

modelo: número de filas para agarrar

 # train data frame from reading the csv train = pd.read_csv(filename) # Get groups of rows with same id csv_by_id = train.groupby('id') modelTarget = { 'f1_t','f2_t','f3_t'} # modelFeatures is a list of features I am interested in the csv. # The csv actually has hundreds modelFeatures = { 'f1, 'f2' , 'f3' } coreFeatures = list(modelFeatures) # cloning selectedFeatures = list(modelFeatures) # cloning newFeatures = list(selectedFeatures) # cloning finalFeatures = list(selectedFeatures) # cloning # Now create the column list depending on the number of rows I will grab from for x in range(2,model+1): newFeatures = [s + '_n' for s in newFeatures] finalFeatures = finalFeatures + newFeatures # This is the final column list for my one row in the final data frame selectedFeatures = finalFeatures + list(modelTarget) # Empty dataframe which I want to populate model_data = pd.DataFrame(columns=selectedFeatures) for id_group in csv_by_id: #id_group is a tuple with first element as the id itself and second one a dataframe with the rows of a group group_data = id_group[1] #hmm - can this be better? I am picking up the rows which I need from first row on wards df = group_data[coreFeatures][0:model] # initialize a list tmp = [] # now keep adding the column values into the list for index, row in df.iterrows(): tmp = tmp + list(row) # Wow, this one below surely should have something better. # So i am picking up the feature column values from the last row of the group of rows for a particular id targetValues = group_data[list({'f1','f2','f3'})][len(group_data.index)-1:len(group_data.index)].values # Think this can be done easier too ? . Basically adding the values to the tmp list again tmp = tmp + list(targetValues.flatten()) # coverting the list to a dict. tmpDict = dict(zip(selectedFeatures,tmp)) # then the dict to a dataframe. tmpDf = pd.DataFrame(tmpDict,index={1}) # I just could not find a better way of adding a dict or list directly into a dataframe. # And I went through lots and lots of blogs on this topic, including some in StackOverflow. # finally I add the frame to my main frame model_data = model_data.append(tmpDf) # and write it model_data.to_csv(wd+'model_data' + str(model) + '.csv',index=False) 

Related of "Procesamiento de datos con la adición de columnas dinámicamente en Python Pandas Dataframe"

Groupby es tu amigo.

Esto se escalará muy bien; Sólo una pequeña constante en el número de características. Será aproximadamente O (número de grupos)

 In [28]: features = ['f1','f2','f3'] 

Cree algunos datos de prueba, los tamaños de grupo son 7-12, 70k grupos

 In [29]: def create_df(i): ....: l = np.random.randint(7,12) ....: df = DataFrame(dict([ (f,np.arange(l)) for f in features ])) ....: df['A'] = i ....: return df ....: In [30]: df = concat([ create_df(i) for i in xrange(70000) ]) In [39]: df.info()  Int64Index: 629885 entries, 0 to 9 Data columns (total 4 columns): f1 629885 non-null int64 f2 629885 non-null int64 f3 629885 non-null int64 A 629885 non-null int64 dtypes: int64(4) 

Cree un marco donde seleccione las primeras 3 filas y la última fila de cada grupo (tenga en cuenta que esto manejará grupos de tamaño <4, sin embargo, su última fila puede superponerse a otra, puede hacer un groupby.filter para remediar esto)

 In [31]: groups = concat([df.groupby('A').head(3),df.groupby('A').tail(1)]).sort_index() # This step is necesary in pandas < master/0.14 as the returned fields # will include the grouping field (the A), (is a bug/API issue) In [33]: groups = groups[features] In [34]: groups.head(20) Out[34]: f1 f2 f3 A 0 0 0 0 0 1 1 1 1 2 2 2 2 7 7 7 7 1 0 0 0 0 1 1 1 1 2 2 2 2 9 9 9 9 2 0 0 0 0 1 1 1 1 2 2 2 2 8 8 8 8 3 0 0 0 0 1 1 1 1 2 2 2 2 8 8 8 8 4 0 0 0 0 1 1 1 1 2 2 2 2 9 9 9 9 [20 rows x 3 columns] In [38]: groups.info()  MultiIndex: 280000 entries, (0, 0) to (69999, 9) Data columns (total 3 columns): f1 280000 non-null int64 f2 280000 non-null int64 f3 280000 non-null int64 dtypes: int64(3) 

Y bastante rapido

 In [32]: %timeit concat([df.groupby('A').head(3),df.groupby('A').tail(1)]).sort_index() 1 loops, best of 3: 1.16 s per loop 

Para una mayor manipulación, por lo general, debería detenerse aquí y usar esto (ya que está en un formato agrupado agradable con el que es fácil lidiar).

Si quieres traducir esto a un formato ancho

 In [35]: dfg = groups.groupby(level=0).apply(lambda x: Series(x.values.ravel())) In [36]: %timeit groups.groupby(level=0).apply(lambda x: Series(x.values.ravel())) dfg.head() groups.info() 1 loops, best of 3: 14.5 s per loop In [40]: dfg.columns = [ "{0}_{1}".format(f,i) for i in range(1,5) for f in features ] In [41]: dfg.head() Out[41]: f1_1 f2_1 f3_1 f1_2 f2_2 f3_2 f1_3 f2_3 f3_3 f1_4 f2_4 f3_4 A 0 0 0 0 1 1 1 2 2 2 7 7 7 1 0 0 0 1 1 1 2 2 2 9 9 9 2 0 0 0 1 1 1 2 2 2 8 8 8 3 0 0 0 1 1 1 2 2 2 8 8 8 4 0 0 0 1 1 1 2 2 2 9 9 9 [5 rows x 12 columns] In [42]: dfg.info()  Int64Index: 70000 entries, 0 to 69999 Data columns (total 12 columns): f1_1 70000 non-null int64 f2_1 70000 non-null int64 f3_1 70000 non-null int64 f1_2 70000 non-null int64 f2_2 70000 non-null int64 f3_2 70000 non-null int64 f1_3 70000 non-null int64 f2_3 70000 non-null int64 f3_3 70000 non-null int64 f1_4 70000 non-null int64 f2_4 70000 non-null int64 f3_4 70000 non-null int64 dtypes: int64(12)