Stack Overflow en español Asked by Durgeoble on November 18, 2021
Tengo un dataframe que contiene una columna de eventos y quiero añadirle una de estado de este modo:
╔═════════════╦═════════════╗
║ eventType ║ estado ║
╠═════════════╬═════════════╣
║ stop ║ 0 ║
╠═════════════╬═════════════╣
║ algo ║ 1 ║
╠═════════════╬═════════════╣
║ algo ║ 1 ║
╠═════════════╬═════════════╣
║ otra cosa ║ 1 ║
╠═════════════╬═════════════╣
║ evento ║ 1 ║
╠═════════════╬═════════════╣
║ ║ 1 ║
╠═════════════╬═════════════╣
║ algo ║ 1 ║
╠═════════════╬═════════════╣
║ otra cosa ║ 1 ║
╠═════════════╬═════════════╣
║ start ║ 1 ║
╠═════════════╬═════════════╣
║ ║ 0 ║
╠═════════════╬═════════════╣
║ algo ║ 0 ║
╠═════════════╬═════════════╣
║ evento ║ 0 ║
╠═════════════╬═════════════╣
║ otro evento ║ 0 ║
╠═════════════╬═════════════╣
║ otra cosa ║ 0 ║
╠═════════════╬═════════════╣
║ stop ║ 0 ║
╠═════════════╬═════════════╣
║ evento ║ 1 ║
╠═════════════╬═════════════╣
║ evento ║ 1 ║
╠═════════════╬═════════════╣
║ otro evento ║ 1 ║
╠═════════════╬═════════════╣
║ algo ║ 1 ║
╠═════════════╬═════════════╣
║ start ║ 1 ║
╠═════════════╬═════════════╣
║ algo algo ║ 0 ║
╠═════════════╬═════════════╣
║ lo que sea ║ 0 ║
╠═════════════╬═════════════╣
║ evento ║ 0 ║
╚═════════════╩═════════════╝
la idea es que cuando encuentre un start empiece a rellenar con 1 y cuando se encuentre un stop con 0 empezando a rellenar con 0 hasta el primer start.
La columna de eventos tiene varios eventos que paran la máquina y varios que la ponen en marcha (aunque la mayoria tienen stop o start en el nombre)
¿hay algún modo de hacerlo sin usar un bucle for?
Solucionado:
Al final he hecho una función:
actual = 0
def def_estado(row):
global actual
events = {'start': 1, 'stop': 0}
if row['eventType'] in events:
actual = events[row['eventType']]
return actual
Y luego se la paso a la la columna con apply
df['estado'] = df.apply(def_estado, axis=1)
Es rara la exigencia de no usar for
.
Nota: No me queda claro en que orden vienen los eventos, por lo tanto, dare dos soluciones
Eventos en orden cronologico
Se supone que los eventos están listados en orden cronológico: el primer evento en la columna es el más antiguo.
La función value
retorna el valor de relleno, segùn el tipo de evento.
El diccionario opciones
tiene como llave el texto del evento y el valor a retornar. También tiene una entrada "last", para guardar el último valor retornado.
La función map
aplica la función value
a toda la columna del Dataframe, produciendo un iterador. La función list
se encarga de transformar lo anterior en una lista. Una vez que tenemos la lista, podemos agregarla como columna al DataFrame por simple asignación.
import pandas as pd
data = ["Inicio", "start", "fecha", "fecha", "stop", "fecha", "fecha", "start", "fecha", "fin"]
df = pd.DataFrame(data, columns=["EventType"])
opciones = dict(stop=0, start=1, last=0)
def value(texto):
if texto in opciones:
opciones['last'] = opciones[texto]
return opciones['last']
df['estado'] = list(map(value, df["EventType"]))
print(df)
produce:
EventType estado
0 Inicio 0
1 start 1
2 fecha 1
3 fecha 1
4 stop 0
5 fecha 0
6 fecha 0
7 start 1
8 fecha 1
9 fin 1
Eventos en orden inverso
Si los eventos vienen en orden inverso (el primero es el más nuevo), vamos a invertir la columna antes de formar la secuencia. Una vez formada la secuencia, la invierto y la agrego como columna al dataframe original.
import pandas as pd
data = ["Inicio", "start", "fecha", "fecha", "stop", "fecha", "fecha", "start", "fecha", "fin"]
df = pd.DataFrame(data, columns=["EventType"])
opciones = dict(stop=0, start=1, last=0)
def value(texto):
if texto in opciones:
opciones['last'] = opciones[texto]
return opciones['last']
events = df["EventType"].values[::-1]
df["estado"] = list(pd.Series(list(map(value, events))))[::-1]
print(df)
produce:
EventType estado
0 Inicio 1
1 start 1
2 fecha 0
3 fecha 0
4 stop 0
5 fecha 1
6 fecha 1
7 start 1
8 fecha 0
9 fin 0
Observaciones
Antes de invocar value()
para un nuevo dataframe, hay que reinicializar opciones['last'] = 0
Answered by Candid Moe on November 18, 2021
DataFrame
s:De manera nativa si puedes generar una colección de datos en base a los elementos de otra, lo que pasa es que la columna de un DataFrame
no es una colección de datos nativa del lenguaje. Si embargo se pueden extraer datos de un DataFrame
como una colección de datos nativa.
¿hay algún modo de hacerlo sin usar un bucle for?
Existe la función implementada map()
:
Return an iterator that applies function to every item of iterable, yielding the results. If additional iterable arguments are passed, function must take that many arguments and is applied to the items from all iterables in parallel.
El DataFrame
que se tiene
En este caso voy a usar un diccionario como manera de creación del DataFrame
, de n * 1
de dimensión. Los valores de la única columna provienen de esta secuencia:
secuencia = ["Inicio",None,None,None,"Final",None,None,None,"Inicio",None,None,None,None,"Indefinido",None,"Final",None,0,"Inicio","Final","Inicio",0,None,0,"Final"]
Donde:
Como dije, si se genera un DataFrame
así
df = pd.DataFrame({"EventType": secuencia})
se obtiene una columna con varias filas
EventType
0 Inicio
1 None
2 None
3 None
4 Final
5 None
6 None
7 None
8 Inicio
9 None
10 None
11 None
12 None
13 Indefinido
14 None
15 Final
16 None
17 0
18 Inicio
19 Final
20 Inicio
21 0
22 None
23 0
24 Final
Extrayendo la columna del DataFrame
Por suerte, podemos acceder a los valores de una columna en específico al igual de comos nos referimos a los valores de una llave en un diccionario. Por medio de el atributo values
y la función list()
se puede obtener en formato de lista los valores de la columna en cuestión. Por lo tanto, se pueden almacenar dichos valores en tipo de dato nativo.
EventType = list(df["EventType"].values)
se obtiene
['Inicio', None, None, None, 'Final', None, None, None, 'Inicio', None, None, None, None, 'Indefinido', None, 'Final', None, 0, 'Inicio', 'Final', 'Inicio', 0, None, 0, 'Final']
Generando la nueva columna del DataFrame
Según la especificación de map()
map(function, iterable, ...)
Requiere de una función y un iterable
Bien puede ser definida o una función anónima, hay que decir que es más conveniente usar una función lambda
anónima. Esto ya que de esa manera al función quedará como una expresión, su tiempo de vida es solo el necesario.
Es necesario que tenga un parámetro, para que itere de uno en uno y ejecute las instrucciones con base a un elemento. Si se usaran más argumentos la cantidad de elementos que se usan por ciclo sería equivalente a la cantidad de argumentos.
Si queremos generar otra lista en base a los elementos de EventType
, es lo que vamos a usar. Se debe de saber cuando empieza o termina un evento. Por la tanto no hay más remedio que definir una función (con una variable de ámbito global):
x = None
def event(n):
global x
if n == "Inicio":
x = 1
elif n == "Final":
x = 0
else:
x = x
return x
De esta manera puede perdurar el valor de x
después de cada iteración que hace map()
. La lista se tendría que generar con una lambda
de un argumento, para que de esta forma todos los elementos de secuencia
pasen por la función event()
state = list(map(lambda n: event(n),secuencia))
Esta expresión, significa añadir un elemento a State
por cada elemento en EventType
. Este elemento será el retornado por event()
.
Se estaría obteniendo esto
[1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0]
DataFrame
final:Se podría montar otro DataFrame
nuevo desde cero, pero es mejor reutilizar el actual y añadir una serie como columna:
df["State"] = pd.Series(state)
A la hora de imprimir por pantalla con print(df)
se obtiene
EventType State
0 Inicio 1
1 None 1
2 None 1
3 None 1
4 Final 0
5 None 0
6 None 0
7 None 0
8 Inicio 1
9 None 1
10 None 1
11 None 1
12 None 1
13 Indefinido 1
14 None 1
15 Final 0
16 None 0
17 0 0
18 Inicio 1
19 Final 0
20 Inicio 1
21 0 1
22 None 1
23 0 1
24 Final 0
Espero te haya servido de algo, saludos.
Answered by user166844 on November 18, 2021
Get help from others!
Recent Questions
Recent Answers
© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP