audeering / audformat

Format to store media files and annotations
https://audeering.github.io/audformat/
Other
9 stars 0 forks source link

Preserve categorical dtype with `map` in `get()` #448

Open hagenw opened 1 week ago

hagenw commented 1 week ago

When requesting a table column with defined categories, dtype category is returned:

>>> import audb
>>> db = audb.load("emodb", version="1.4.1", only_metadata=True, full_path=False)
>>> db["files"]["transcription"].get().head()
file
wav/03a01Fa.wav    a01
wav/03a01Nc.wav    a01
wav/03a01Wa.wav    a01
wav/03a02Fc.wav    a02
wav/03a02Nc.wav    a02
Name: transcription, dtype: category
Categories (10, object): ['a01', 'a02', 'a04', 'a05', ..., 'b02', 'b03', 'b09', 'b10']

But when using map to map to labels defined by the scheme, we loose the category dtype:

>>> db["files"]["transcription"].get(map=True).head()
file
wav/03a01Fa.wav    Der Lappen liegt auf dem Eisschrank.
wav/03a01Nc.wav    Der Lappen liegt auf dem Eisschrank.
wav/03a01Wa.wav    Der Lappen liegt auf dem Eisschrank.
wav/03a02Fc.wav       Das will sie am Mittwoch abgeben.
wav/03a02Nc.wav       Das will sie am Mittwoch abgeben.
Name: True, dtype: string

I'm not sure yet if this is a feature or a bug, but it feels strange to me, that we loose the category dtype.


The same holds true, when the scheme labels are given by a misc table:

>>> db["files"]["speaker"].get().head()
file
wav/03a01Fa.wav    3
wav/03a01Nc.wav    3
wav/03a01Wa.wav    3
wav/03a02Fc.wav    3
wav/03a02Nc.wav    3
Name: speaker, dtype: category
Categories (10, int64): [3, 8, 9, 10, ..., 13, 14, 15, 16]

>>> db["files"]["speaker"].get(map="age").head()
file
wav/03a01Fa.wav    31
wav/03a01Nc.wav    31
wav/03a01Wa.wav    31
wav/03a02Fc.wav    31
wav/03a02Nc.wav    31
Name: age, dtype: Int64
ChristianGeng commented 1 week ago

I am wondering about the behavior when map=False:

>>> import audb
>>> audb.load("emodb", version="1.4.1", only_metadata=True, full_path=False)
>>> print(db["files"]["transcription"].get().head())

file
wav/03a01Fa.wav    a01
wav/03a01Nc.wav    a01
wav/03a01Wa.wav    a01
wav/03a02Fc.wav    a02
wav/03a02Nc.wav    a02
Name: transcription, dtype: category
Categories (10, object): ['a01', 'a02', 'a04', 'a05', ..., 'b02', 'b03', 'b09', 'b10']

>>> print(db["files"]["transcription"].get(map=True).head())

file
wav/03a01Fa.wav    Der Lappen liegt auf dem Eisschrank.
wav/03a01Nc.wav    Der Lappen liegt auf dem Eisschrank.
wav/03a01Wa.wav    Der Lappen liegt auf dem Eisschrank.
wav/03a02Fc.wav       Das will sie am Mittwoch abgeben.
wav/03a02Nc.wav       Das will sie am Mittwoch abgeben.
Name: True, dtype: string

>>> print(db["files"]["transcription"].get(map=False).head())

file
wav/03a01Fa.wav    Der Lappen liegt auf dem Eisschrank.
wav/03a01Nc.wav    Der Lappen liegt auf dem Eisschrank.
wav/03a01Wa.wav    Der Lappen liegt auf dem Eisschrank.
wav/03a02Fc.wav       Das will sie am Mittwoch abgeben.
wav/03a02Nc.wav       Das will sie am Mittwoch abgeben.
Name: False, dtype: string

In words, when I do map=False I am also mapped data.

This is the type hint for the map param in table.get :

map: typing.Dict[str, typing.Union[str, typing.Sequence[str]]] = None,

I had so far always used it more like this:

>>> print(db["files"]["transcription"].get(map="transcription"))
file
wav/03a01Fa.wav                 Der Lappen liegt auf dem Eisschrank.
wav/03a01Nc.wav                 Der Lappen liegt auf dem Eisschrank.
wav/03a01Wa.wav                 Der Lappen liegt auf dem Eisschrank.
wav/03a02Fc.wav                    Das will sie am Mittwoch abgeben.
wav/03a02Nc.wav                    Das will sie am Mittwoch abgeben.
                                         ...                        
wav/16b10Lb.wav    Die wird auf dem Platz sein, wo wir sie immer ...
wav/16b10Tb.wav    Die wird auf dem Platz sein, wo wir sie immer ...
wav/16b10Td.wav    Die wird auf dem Platz sein, wo wir sie immer ...
wav/16b10Wa.wav    Die wird auf dem Platz sein, wo wir sie immer ...
wav/16b10Wb.wav    Die wird auf dem Platz sein, wo wir sie immer ...
Name: transcription, Length: 535, dtype: string
hagenw commented 6 days ago

You are right map=True and map=False are not desired use cases for audformat.Column.get(), I guess I was confused from the map argument of audformat.Database.get():

image


db["files"]["transcription"].get(map="transcription")

is the correct call at the moment, even though there is anyway no other available choice than transcription.

hagenw commented 6 days ago

Maybe we also extend audformat.Column.get() to support map=True if only a single option is available. But I'm not completely sure, if this is a good idea as it would make audformat.Column.get(map=...) more complex.