projectmesa / mesa

Mesa is an open-source Python library for agent-based modeling, ideal for simulating complex systems and exploring emergent behaviors.
https://mesa.readthedocs.io
Apache License 2.0
2.45k stars 874 forks source link

DataCollector requires all agents to have the same Attributes #976

Closed JonasJosef123 closed 1 week ago

JonasJosef123 commented 3 years ago

What's the problem this feature will solve? Hello @all I am not sure if I am actually doing something wrong but in my code I have two different agents types that get different attributes when created. (however they are from the same agent class) When I want to collect their specific attribute data with the data collector i get an "AttributeError" that my agents object has no such attribute. While this is true for agents 1-4 i created, agents 5-20 have that specific attribute. The only solution I found was to create the same attribute for the first 4 agents aswell and initialize it with None. For me this makes the code unnecessary flatulent. Is there a smart way around? For me it would be intuitive to check if the agent has this attribute and if not to automatically put "None" as a placeholder for the datacollector.

I am not really experience with python and mesa so I dont know if there exist some best practice solution to create different agents only through different classes or something like this.

Thanks for your help!

best regards,

Jonas

jackiekazil commented 3 years ago

I would add the attribute with a default of None. I can't think of another way. Depending on the data type of the attribute, there are nice ways to write / come to the conclusion of None.

rht commented 3 years ago

@JonasJosef123 there is one alternative solution: in the data collector, instead of doing a.foo, you do getattr(a, 'foo', None). It basically tries to check if a has attribute 'foo', if not, fall back to default that is None. If this solves your case, you can close this issue.

rht commented 3 years ago

It's similar to the dictionary method get that sometimes you'd want to use: https://stackoverflow.com/questions/11041405/why-dict-getkey-instead-of-dictkey.

TabernaA commented 3 years ago

Hello everybody! It works fine using None, yet if I have 5,000 households and 500 firms in my model and I would like to get only firms attributes, I end up with very big DataFrames and slow down the model. It would be great to add something like an agent data collector that works only for a specific type/class/breed. Best Ale

tpike3 commented 3 years ago

@TabernaA I would have to take a deeper look, but I think this is possible. For a maybe a quick solution did you look at the the Wolf-Sheep example which uses breeds of agents? https://github.com/projectmesa/mesa/tree/master/examples/wolf_sheep

TabernaA commented 3 years ago

Yes, I do. But what I need is not the breed count but agent level variable. I am simply using lambda with the 'if condition' to keep only the type of agent I need and put None otherwise. The only problem is that it slows down a little bit the run and I have to manipulate a bit the dataframe afterwards.

rht commented 3 years ago

@TabernaA does https://github.com/projectmesa/mesa/issues/976#issuecomment-776648380 not answer the problem with defaulting to None?

EwoutH commented 2 years ago

@JonasJosef123 In the last month there has been some discussion about this feature going on in #1419, you might find that interesting to follow! :)

quaquel commented 1 week ago

closed via #2300

EwoutH commented 1 week ago

Yes, we added the agenttype_reporters argument which allows collecting different variables from different Agent classes.

self.datacollector = DataCollector(
    agenttype_reporters={
        Wolf: {"sheep_eaten": "sheep_eaten"},
        Sheep: {"wool": "wool_amount"}
    }
)

See #2300 for details indeed!