[1]:
import logging

logging.basicConfig(level=logging.INFO)

from pystatis import Table

The Table Class

The Table class in pystatis is the main interface for users to interact with the different databases and download the data/tables in form of pandas DataFrames.

To use the class, you have to pass only a single parameter: the name of the table you want to download.

[2]:
t = Table(name="81000-0001")

Downloading data

However, creating a new Table instance does not automatically retrieve the data from the database (or cache). Instead, you have to call another method: get_data(). The reason for this decision was to give you full control over the download process and avoid unnecessary downloads of big tables unless you are certain you want to start the download.

[3]:
t.get_data()
INFO:pystatis.http_helper:Code 0: erfolgreich

You can access the name of a table via the .name attribute.

[4]:
t.name
[4]:
'81000-0001'

After a successful download (or cache retrieval), you can always access the raw data, that is the original response from the web API as a string, via the .raw_data attribute.

[5]:
print(t.raw_data)
Statistik_Code;Statistik_Label;Zeit_Code;Zeit_Label;Zeit;1_Merkmal_Code;1_Merkmal_Label;1_Auspraegung_Code;1_Auspraegung_Label;2_Merkmal_Code;2_Merkmal_Label;2_Auspraegung_Code;2_Auspraegung_Label;BWS001__Bruttowertschoepfung__jew._ME;STR006__Guetersteuern_abzuegl._Guetersubventionen__jew._ME;STR020_______Guetersteuern__jew._ME;SUB003_______Guetersubventionen__jew._ME;VGR014__Bruttoinlandsprodukt__jew._ME;BIP005__nachr.:_Bruttoinlandsprodukt_(Veraenderung_in_%)__Prozent;BIP004__nachr.:_Bruttoinlandsprodukt_je_Einwohner__jew._ME
81000;Volkswirtschaftliche Gesamtrechnungen des Bundes;JAHR;Jahr;2014;DINSG;Deutschland insgesamt;DG;Deutschland;VGRPB5;Preisbasis;VGRJPM;in jeweiligen Preisen (Mrd. EUR);2635,393;292,037;298,774;6,737;2927,430;4,1;36149,000
81000;Volkswirtschaftliche Gesamtrechnungen des Bundes;JAHR;Jahr;2014;DINSG;Deutschland insgesamt;DG;Deutschland;VGRPB5;Preisbasis;VGRPKM;preisbereinigt, Kettenindex (2015=100);98,810;96,150;96,250;100,970;98,530;2,2;99,380
81000;Volkswirtschaftliche Gesamtrechnungen des Bundes;JAHR;Jahr;2014;DINSG;Deutschland insgesamt;DG;Deutschland;VGRPB5;Preisbasis;VGRPVK;preisbereinigt, verkettete Volumenang. (Mrd. EUR);2689,628;-;-;-;2981,695;2,2;-
81000;Volkswirtschaftliche Gesamtrechnungen des Bundes;JAHR;Jahr;2014;DINSG;Deutschland insgesamt;DG;Deutschland;VGRPB5;Preisbasis;VGRPVU;preisbereinigt, unverkettete Volumenang.(Mrd. EUR);2584,829;-;-;-;2873,722;-;-
81000;Volkswirtschaftliche Gesamtrechnungen des Bundes;JAHR;Jahr;2015;DINSG;Deutschland insgesamt;DG;Deutschland;VGRPB5;Preisbasis;VGRJPM;in jeweiligen Preisen (Mrd. EUR);2722,020;304,160;310,942;6,782;3026,180;3,4;37046,000
81000;Volkswirtschaftliche Gesamtrechnungen des Bundes;JAHR;Jahr;2015;DINSG;Deutschland insgesamt;DG;Deutschland;VGRPB5;Preisbasis;VGRPKM;preisbereinigt, Kettenindex (2015=100);100,000;100,000;100,000;100,000;100,000;1,5;100,000
81000;Volkswirtschaftliche Gesamtrechnungen des Bundes;JAHR;Jahr;2015;DINSG;Deutschland insgesamt;DG;Deutschland;VGRPB5;Preisbasis;VGRPVK;preisbereinigt, verkettete Volumenang. (Mrd. EUR);2722,020;-;-;-;3026,180;1,5;-
81000;Volkswirtschaftliche Gesamtrechnungen des Bundes;JAHR;Jahr;2015;DINSG;Deutschland insgesamt;DG;Deutschland;VGRPB5;Preisbasis;VGRPVU;preisbereinigt, unverkettete Volumenang.(Mrd. EUR);2667,231;-;-;-;2970,965;-;-
81000;Volkswirtschaftliche Gesamtrechnungen des Bundes;JAHR;Jahr;2016;DINSG;Deutschland insgesamt;DG;Deutschland;VGRPB5;Preisbasis;VGRJPM;in jeweiligen Preisen (Mrd. EUR);2822,443;312,297;319,143;6,846;3134,740;3,6;38067,000
81000;Volkswirtschaftliche Gesamtrechnungen des Bundes;JAHR;Jahr;2016;DINSG;Deutschland insgesamt;DG;Deutschland;VGRPB5;Preisbasis;VGRPKM;preisbereinigt, Kettenindex (2015=100);102,250;102,030;101,990;100,240;102,230;2,2;101,410
81000;Volkswirtschaftliche Gesamtrechnungen des Bundes;JAHR;Jahr;2016;DINSG;Deutschland insgesamt;DG;Deutschland;VGRPB5;Preisbasis;VGRPVK;preisbereinigt, verkettete Volumenang. (Mrd. EUR);2783,265;-;-;-;3093,664;2,2;-
81000;Volkswirtschaftliche Gesamtrechnungen des Bundes;JAHR;Jahr;2016;DINSG;Deutschland insgesamt;DG;Deutschland;VGRPB5;Preisbasis;VGRPVU;preisbereinigt, unverkettete Volumenang.(Mrd. EUR);2783,371;-;-;-;3093,710;-;-
81000;Volkswirtschaftliche Gesamtrechnungen des Bundes;JAHR;Jahr;2017;DINSG;Deutschland insgesamt;DG;Deutschland;VGRPB5;Preisbasis;VGRJPM;in jeweiligen Preisen (Mrd. EUR);2944,074;323,086;329,847;6,761;3267,160;4,2;39527,000
81000;Volkswirtschaftliche Gesamtrechnungen des Bundes;JAHR;Jahr;2017;DINSG;Deutschland insgesamt;DG;Deutschland;VGRPB5;Preisbasis;VGRPKM;preisbereinigt, Kettenindex (2015=100);105,110;103,760;103,700;101,290;104,970;2,7;103,740
81000;Volkswirtschaftliche Gesamtrechnungen des Bundes;JAHR;Jahr;2017;DINSG;Deutschland insgesamt;DG;Deutschland;VGRPB5;Preisbasis;VGRPVK;preisbereinigt, verkettete Volumenang. (Mrd. EUR);2861,115;-;-;-;3176,581;2,7;-
81000;Volkswirtschaftliche Gesamtrechnungen des Bundes;JAHR;Jahr;2017;DINSG;Deutschland insgesamt;DG;Deutschland;VGRPB5;Preisbasis;VGRPVU;preisbereinigt, unverkettete Volumenang.(Mrd. EUR);2901,242;-;-;-;3218,826;-;-
81000;Volkswirtschaftliche Gesamtrechnungen des Bundes;JAHR;Jahr;2018;DINSG;Deutschland insgesamt;DG;Deutschland;VGRPB5;Preisbasis;VGRJPM;in jeweiligen Preisen (Mrd. EUR);3032,736;332,714;339,600;6,886;3365,450;3,0;40594,000
81000;Volkswirtschaftliche Gesamtrechnungen des Bundes;JAHR;Jahr;2018;DINSG;Deutschland insgesamt;DG;Deutschland;VGRPB5;Preisbasis;VGRPKM;preisbereinigt, Kettenindex (2015=100);106,100;105,160;105,070;101,020;106,000;1,0;104,440
81000;Volkswirtschaftliche Gesamtrechnungen des Bundes;JAHR;Jahr;2018;DINSG;Deutschland insgesamt;DG;Deutschland;VGRPB5;Preisbasis;VGRPVK;preisbereinigt, verkettete Volumenang. (Mrd. EUR);2888,063;-;-;-;3207,751;1,0;-
81000;Volkswirtschaftliche Gesamtrechnungen des Bundes;JAHR;Jahr;2018;DINSG;Deutschland insgesamt;DG;Deutschland;VGRPB5;Preisbasis;VGRPVU;preisbereinigt, unverkettete Volumenang.(Mrd. EUR);2971,786;-;-;-;3299,232;-;-
81000;Volkswirtschaftliche Gesamtrechnungen des Bundes;JAHR;Jahr;2019;DINSG;Deutschland insgesamt;DG;Deutschland;VGRPB5;Preisbasis;VGRJPM;in jeweiligen Preisen (Mrd. EUR);3130,567;343,543;350,942;7,399;3474,110;3,2;41810,000
81000;Volkswirtschaftliche Gesamtrechnungen des Bundes;JAHR;Jahr;2019;DINSG;Deutschland insgesamt;DG;Deutschland;VGRPB5;Preisbasis;VGRPKM;preisbereinigt, Kettenindex (2015=100);107,000;108,390;108,240;101,420;107,140;1,1;105,330
81000;Volkswirtschaftliche Gesamtrechnungen des Bundes;JAHR;Jahr;2019;DINSG;Deutschland insgesamt;DG;Deutschland;VGRPB5;Preisbasis;VGRPVK;preisbereinigt, verkettete Volumenang. (Mrd. EUR);2912,561;-;-;-;3242,249;1,1;-
81000;Volkswirtschaftliche Gesamtrechnungen des Bundes;JAHR;Jahr;2019;DINSG;Deutschland insgesamt;DG;Deutschland;VGRPB5;Preisbasis;VGRPVU;preisbereinigt, unverkettete Volumenang.(Mrd. EUR);3058,504;-;-;-;3401,440;-;-
81000;Volkswirtschaftliche Gesamtrechnungen des Bundes;JAHR;Jahr;2020;DINSG;Deutschland insgesamt;DG;Deutschland;VGRPB5;Preisbasis;VGRJPM;in jeweiligen Preisen (Mrd. EUR);3086,377;317,353;325,967;8,614;3403,730;-2,0;40929,000
81000;Volkswirtschaftliche Gesamtrechnungen des Bundes;JAHR;Jahr;2020;DINSG;Deutschland insgesamt;DG;Deutschland;VGRPB5;Preisbasis;VGRPKM;preisbereinigt, Kettenindex (2015=100);102,670;106,400;105,560;68,580;103,040;-3,8;101,220
81000;Volkswirtschaftliche Gesamtrechnungen des Bundes;JAHR;Jahr;2020;DINSG;Deutschland insgesamt;DG;Deutschland;VGRPB5;Preisbasis;VGRPVK;preisbereinigt, verkettete Volumenang. (Mrd. EUR);2794,698;-;-;-;3118,176;-3,8;-
81000;Volkswirtschaftliche Gesamtrechnungen des Bundes;JAHR;Jahr;2020;DINSG;Deutschland insgesamt;DG;Deutschland;VGRPB5;Preisbasis;VGRPVU;preisbereinigt, unverkettete Volumenang.(Mrd. EUR);3003,872;-;-;-;3341,107;-;-
81000;Volkswirtschaftliche Gesamtrechnungen des Bundes;JAHR;Jahr;2021;DINSG;Deutschland insgesamt;DG;Deutschland;VGRPB5;Preisbasis;VGRJPM;in jeweiligen Preisen (Mrd. EUR);3276,377;341,073;365,141;24,068;3617,450;6,3;43481,000
81000;Volkswirtschaftliche Gesamtrechnungen des Bundes;JAHR;Jahr;2021;DINSG;Deutschland insgesamt;DG;Deutschland;VGRPB5;Preisbasis;VGRPKM;preisbereinigt, Kettenindex (2015=100);106,060;108,380;107,530;70,100;106,300;3,2;104,370
81000;Volkswirtschaftliche Gesamtrechnungen des Bundes;JAHR;Jahr;2021;DINSG;Deutschland insgesamt;DG;Deutschland;VGRPB5;Preisbasis;VGRPVK;preisbereinigt, verkettete Volumenang. (Mrd. EUR);2886,974;-;-;-;3216,829;3,2;-
81000;Volkswirtschaftliche Gesamtrechnungen des Bundes;JAHR;Jahr;2021;DINSG;Deutschland insgesamt;DG;Deutschland;VGRPB5;Preisbasis;VGRPVU;preisbereinigt, unverkettete Volumenang.(Mrd. EUR);3188,250;-;-;-;3511,508;-;-
81000;Volkswirtschaftliche Gesamtrechnungen des Bundes;JAHR;Jahr;2022;DINSG;Deutschland insgesamt;DG;Deutschland;VGRPB5;Preisbasis;VGRJPM;in jeweiligen Preisen (Mrd. EUR);3509,628;367,182;390,670;23,488;3876,810;7,2;46264,000
81000;Volkswirtschaftliche Gesamtrechnungen des Bundes;JAHR;Jahr;2022;DINSG;Deutschland insgesamt;DG;Deutschland;VGRPB5;Preisbasis;VGRPKM;preisbereinigt, Kettenindex (2015=100);107,860;111,470;108,370;50,060;108,220;1,8;105,500
81000;Volkswirtschaftliche Gesamtrechnungen des Bundes;JAHR;Jahr;2022;DINSG;Deutschland insgesamt;DG;Deutschland;VGRPB5;Preisbasis;VGRPVK;preisbereinigt, verkettete Volumenang. (Mrd. EUR);2935,971;-;-;-;3274,932;1,8;-
81000;Volkswirtschaftliche Gesamtrechnungen des Bundes;JAHR;Jahr;2022;DINSG;Deutschland insgesamt;DG;Deutschland;VGRPB5;Preisbasis;VGRPVU;preisbereinigt, unverkettete Volumenang.(Mrd. EUR);3331,942;-;-;-;3682,747;-;-
81000;Volkswirtschaftliche Gesamtrechnungen des Bundes;JAHR;Jahr;2023;DINSG;Deutschland insgesamt;DG;Deutschland;VGRPB5;Preisbasis;VGRJPM;in jeweiligen Preisen (Mrd. EUR);3767,909;354,301;390,660;36,359;4122,210;6,3;48775,000
81000;Volkswirtschaftliche Gesamtrechnungen des Bundes;JAHR;Jahr;2023;DINSG;Deutschland insgesamt;DG;Deutschland;VGRPB5;Preisbasis;VGRPKM;preisbereinigt, Kettenindex (2015=100);107,930;108,460;104,270;39,670;108,010;-0,2;104,400
81000;Volkswirtschaftliche Gesamtrechnungen des Bundes;JAHR;Jahr;2023;DINSG;Deutschland insgesamt;DG;Deutschland;VGRPB5;Preisbasis;VGRPVK;preisbereinigt, verkettete Volumenang. (Mrd. EUR);2937,876;-;-;-;3268,577;-0,2;-
81000;Volkswirtschaftliche Gesamtrechnungen des Bundes;JAHR;Jahr;2023;DINSG;Deutschland insgesamt;DG;Deutschland;VGRPB5;Preisbasis;VGRPVU;preisbereinigt, unverkettete Volumenang.(Mrd. EUR);3511,999;-;-;-;3869,273;-;-

More likely, you are interested in the pandas DataFrame, which is accessible via the .data attribute.

[6]:
t.data.head()
[6]:
Jahr Deutschland insgesamt Preisbasis Bruttowertschoepfung__jew._ME Guetersteuern_abzuegl._Guetersubventionen__jew._ME Guetersteuern__jew._ME Guetersubventionen__jew._ME Bruttoinlandsprodukt__jew._ME nachr.:_Bruttoinlandsprodukt_(Veraenderung_in_%)__Prozent nachr.:_Bruttoinlandsprodukt_je_Einwohner__jew._ME
0 2014 Deutschland in jeweiligen Preisen (Mrd. EUR) 2635.393 292.037 298.774 6.737 2927.430 4.1 36149.00
1 2014 Deutschland preisbereinigt, Kettenindex (2015=100) 98.810 96.150 96.250 100.970 98.530 2.2 99.38
2 2014 Deutschland preisbereinigt, verkettete Volumenang. (Mrd. EUR) 2689.628 NaN NaN NaN 2981.695 2.2 NaN
3 2014 Deutschland preisbereinigt, unverkettete Volumenang.(Mrd. EUR) 2584.829 NaN NaN NaN 2873.722 NaN NaN
4 2015 Deutschland in jeweiligen Preisen (Mrd. EUR) 2722.020 304.160 310.942 6.782 3026.180 3.4 37046.00

Finally, you can also access the metadata for this table via the .metadata attribute.

[7]:
from pprint import pprint

pprint(t.metadata)
{'Copyright': '© Statistisches Bundesamt (Destatis), 2024',
 'Ident': {'Method': 'table', 'Service': 'metadata'},
 'Object': {'Code': '81000-0001',
            'Content': 'VGR des Bundes - Bruttowertschöpfung, '
                       'Bruttoinlandsprodukt\n'
                       '(nominal/preisbereinigt): Deutschland, Jahre',
            'Structure': {'Columns': [{'Code': 'JAHR',
                                       'Content': 'Jahr',
                                       'Selected': '10',
                                       'Structure': None,
                                       'Type': 'Merkmal',
                                       'Updated': 'see parent',
                                       'Values': '10'}],
                          'Head': {'Code': '81000',
                                   'Content': 'Volkswirtschaftliche '
                                              'Gesamtrechnungen des Bundes',
                                   'Selected': None,
                                   'Structure': [{'Code': 'DINSG',
                                                  'Content': 'Deutschland '
                                                             'insgesamt',
                                                  'Selected': '1',
                                                  'Structure': None,
                                                  'Type': 'Merkmal',
                                                  'Updated': 'see parent',
                                                  'Values': '1'}],
                                   'Type': 'Statistik',
                                   'Updated': 'see parent',
                                   'Values': None},
                          'Rows': [{'Code': 'BWS001',
                                    'Content': 'Bruttowertschöpfung',
                                    'Selected': None,
                                    'Structure': None,
                                    'Type': 'Merkmal',
                                    'Updated': 'see parent',
                                    'Values': None},
                                   {'Code': 'STR006',
                                    'Content': 'Gütersteuern abzügl. '
                                               'Gütersubventionen',
                                    'Selected': None,
                                    'Structure': None,
                                    'Type': 'Merkmal',
                                    'Updated': 'see parent',
                                    'Values': None},
                                   {'Code': 'STR020',
                                    'Content': 'Gütersteuern',
                                    'Selected': None,
                                    'Structure': None,
                                    'Type': 'Merkmal',
                                    'Updated': 'see parent',
                                    'Values': None},
                                   {'Code': 'SUB003',
                                    'Content': 'Gütersubventionen',
                                    'Selected': None,
                                    'Structure': None,
                                    'Type': 'Merkmal',
                                    'Updated': 'see parent',
                                    'Values': None},
                                   {'Code': 'VGR014',
                                    'Content': 'Bruttoinlandsprodukt',
                                    'Selected': None,
                                    'Structure': None,
                                    'Type': 'Merkmal',
                                    'Updated': 'see parent',
                                    'Values': None},
                                   {'Code': 'BIP005',
                                    'Content': 'Bruttoinlandsprodukt '
                                               '(Veränderung in %)',
                                    'Selected': None,
                                    'Structure': None,
                                    'Type': 'Merkmal',
                                    'Updated': 'see parent',
                                    'Values': None},
                                   {'Code': 'BIP004',
                                    'Content': 'Bruttoinlandsprodukt je '
                                               'Einwohner',
                                    'Selected': None,
                                    'Structure': None,
                                    'Type': 'Merkmal',
                                    'Updated': 'see parent',
                                    'Values': None}],
                          'Subheading': {'Code': 'VGRPB5',
                                         'Content': 'Preisbasis (jeweilige '
                                                    'Preise / preisbereinigt)',
                                         'Selected': None,
                                         'Structure': None,
                                         'Type': 'Merkmal',
                                         'Updated': 'see parent',
                                         'Values': None},
                          'Subtitel': None},
            'Time': {'From': '1991', 'To': '2023'},
            'Updated': '28.12.2022 17:19:48h',
            'Valid': 'false'},
 'Parameter': {'area': 'Alle',
               'language': 'de',
               'name': '81000-0001',
               'password': '********************',
               'username': '********************'},
 'Status': {'Code': 0, 'Content': 'erfolgreich', 'Type': 'Information'}}

How pystatis prepares the data for you

As you can notice from a comparison between the .raw_data and .data formats, pystatis is doing a lot behind the scenes to provide you with a format that is hopefully the most useful for you. You will see and learn that there are a few parameters that you can use to actually change this behavior and adjust the table to your needs.

But first we would like to explain to you how pystatis is preparing the data by default so you have a better understanding of the underlying process.

When we look at the header of the raw data, we can notice a few things: - Many columns always come in a pair of *_Code and *_Label columns. Both contain the same information, only provided differently. - There are columns that don’t have a direct use as they contain information not needed in the table, like the Statistik_Code and Statistik_Label columns at the beginning. You already know the statistic from the name of the table and this information is the same for each and every row anyway. - There is always a time dimension, broken down into three different columns Zeit_Code, Zeit_Label and Zeit (or time_* in English). - The other dimensions are called variables (German “Merkmale”) and they always come in groups of four columns: N_Merkmal_Code, N_Merkmal_Label, N_Auspraegung_Code, and N_Auspraegung_Label (English: variable code and label and variable value code and label). - The actual measurements or values are at the end of the table after the variables and each measurement has one column. The name of this column follows the format <CODE>__<LABEL>__<UNIT>, e.g. “BWS001__Bruttowertschoepfung__jew._ME”. “BWS001” is the unique code for this variable, “Bruttowertschoepfung” is the human readable label of the variable, and “jew._ME” is the unit the measurement was recorded in.

Note This is only true for tables from Genesis and Regionalstatistik, the format of the Zensus tables is noticeably different from this. However, we follow a similar approach to provide you the same convenient output format.

The following table hopefully makes it a little bit clearer what is happening when going from the raw data string to the pandas DataFrame. The example is showing the Table “11111-02-01-4” from Regionalstatistik, but remember, that Genesis and Regionalstatistik have identically formats. The table has a time dimension, one attribute and one value.

Statistik_Code

Statistik_Label

Zeit_Code

Zeit_Label

Zeit

1_Merkmal_Code

1_Merkmal_Label

1_Auspraegung_Code

1_Auspraegung_Label

GEM001__Zahl_der_Gemeinden__Anzahl

11111

Feststellung des Gebietsstandes

STAG

Stichtag

31.12.2022

KREISE

Kreise und kreisfreie Städte

DG

Deutschland

10786

11111

Feststellung des Gebietsstandes

STAG

Stichtag

31.12.2022

KREISE

Kreise und kreisfreie Städte

01

Schleswig-Holstein

1106

The same table has the following pandas representation after being “prettified” by pystatis:

[8]:
t = Table("11111-02-01-4")
t.get_data()
t.data.head(2)
INFO:pystatis.http_helper:Code 0: erfolgreich
[8]:
Stichtag Amtlicher Gemeindeschlüssel (AGS) Kreise und kreisfreie Städte Zahl_der_Gemeinden__Anzahl
0 2022-12-31 DG Deutschland 10786.0
1 2022-12-31 01 Schleswig-Holstein 1106.0

As you can see and hopefully agree, the pandas version (what we call “prettified”) provides the same information, actually even more, because the header column names have become meaningful and there is a lot less noise that you need to filter out before you can get to the actual data.

For Zensus pystatis is basically doing the same, but in a slightly different way because since the release of Zensus 2022 the API no longer returns each measurement as a single column but only a single column for all values. pystatis is transforming this long data format back into a wide data format, so you can work with a tidy data set. See the following example of Table “4000W-1002” to understand what is going on.

statistics_code

statistics_label

time_code

time_label

time

1_variable_code

1_variable_label

1_variable_attribute_code

1_variable_attribute_label

2_variable_code

2_variable_label

2_variable_attribute_code

2_variable_attribute_label

value

value_unit

value_variable_code

value_variable_label

4000W

Wohnungen (Gebietsstand 15.05.2022)

STAG

Stichtag

2022-05-15

GEODL1

Deutschland

DG

Deutschland

WHGFL2

Fläche der Wohnung (10 m²-Intervalle)

WFL170B179

170 - 179 m²

1,2

%

WHG002

Wohnungen in Gebäuden mit Wohnraum

4000W

Wohnungen (Gebietsstand 15.05.2022)

STAG

Stichtag

2022-05-15

GEODL1

Deutschland

DG

Deutschland

WHGFL2

Fläche der Wohnung (10 m²-Intervalle)

WFL170B179

170 - 179 m²

509041

Anzahl

WHG002

Wohnungen in Gebäuden mit Wohnraum

4000W

Wohnungen (Gebietsstand 15.05.2022)

STAG

Stichtag

2022-05-15

GEODL1

Deutschland

DG

Deutschland

WHGFL2

Fläche der Wohnung (10 m²-Intervalle)

WFL090B099

90 - 99 m²

7,2

%

WHG002

Wohnungen in Gebäuden mit Wohnraum

4000W

Wohnungen (Gebietsstand 15.05.2022)

STAG

Stichtag

2022-05-15

GEODL1

Deutschland

DG

Deutschland

WHGFL2

Fläche der Wohnung (10 m²-Intervalle)

WFL090B099

90 - 99 m²

3082890

Anzahl

WHG002

Wohnungen in Gebäuden mit Wohnraum

[10]:
t = Table("4000W-1002")
t.get_data()
t.data.head(2)
INFO:pystatis.cache:Data was successfully cached under /Users/miay/.pystatis/data/4000W-1002/3d1d8e69a7d4397b08b0/20240713.zip.
INFO:pystatis.http_helper:Code 0: erfolgreich
[10]:
Stichtag Deutschland Fläche der Wohnung (10 m²-Intervalle) Wohnungen in Gebäuden mit Wohnraum__% Wohnungen in Gebäuden mit Wohnraum__Anzahl
0 2022-05-15 Deutschland Insgesamt 100.0 43106589.0
1 2022-05-15 Deutschland Unter 30 m² 2.1 909120.0

As you can see, pystatis is not only increasing readability and making data access easy, it also reduces the amount of data you have to work with. Going from a long format back to a tidy wide format means cutting the number of rows to 1/3 because all three measurements get back their own column.

pystatis is doing the following things (by default) when parsing the original raw string: - remove the information about the statistic - for all variables: only keep the value column and choose the variable label as the column name - for all measurements: remove the variable code from the column name, only keep label and unit - set the proper data types (datetime for the time variable, if appropriate; str for regional codes) - handling missing values (i.e. replacing characters “…”, “.”, “-”, “/” and “x” by proper NaN values) and special characters - choosing the right decimal character depending on the specified language (German: “,”, English: “.”)

All of this happens behind the scenes when you are downloading the data with get_data() and access it via the Table.data attribute.

All get_data() parameters explained

You can find a list of all parameters in the documentation or in the docstring. All parameters are keyword parameters only (fancy Python star syntax: f(*, everything from here on has to be a keyword only parameter)).

[10]:
?t.get_data
Signature:
t.get_data(
    *,
    prettify: bool = True,
    area: str = 'all',
    startyear: str = '',
    endyear: str = '',
    timeslices: str = '',
    regionalvariable: str = '',
    regionalkey: str = '',
    stand: str = '',
    language: str = 'de',
    quality: bool = False,
)
Docstring:
Downloads raw data and metadata from GENESIS-Online.

Additional keyword arguments are passed on to the GENESIS-Online GET request for tablefile.

Args:
    prettify (bool, optional): Reformats the table into a readable format. Defaults to True.
    area (str, optional): Area to search for the object in GENESIS-Online. Defaults to "all".
    startyear (str, optional): Data beginning with that year will be returned.
        Parameter is cumulative to `timeslices`. Supports 4 digits (jjjj) or 4+2 digits (jjjj/jj).
        Accepts values between "1900" and "2100".
    endyear (str, optional): Data ending with that year will be returned.
        Parameter is cumulative to `timeslices`. Supports 4 digits (jjjj) or 4+2 digits (jjjj/jj).
        Accepts values between "1900" and "2100".
    timeslices (str, optional): Number of time slices to be returned.
        This parameter is cumulative to `startyear` and `endyear`.
    regionalvariable (str, optional): "code" of the regional classification (RKMerkmal),
        to which the selection using `regionalkey` is to be applied.
        Accepts 1-6 characters.
        Possible values:
        - Regionalstatistik (only for tables ending with "B", see /catalogue/variables):
            - "DG" (Deutschland, 1) -> will not return extra column
            - "DLAND" (Bundesländer, 16)
            - "REGBEZ" (Regierungsbezirke, 44)
            - "KREISE" (Kreise und kreisfreie Städte, 489)
            - "GEMEIN" (Gemeinden, 13564)
        - Zensusdatenbank (for all tables, see /catalogue/variables):
            - "GEODL1" (Deutschland, 1) -> will not return extra column
            - "GEODL3" (Deutschland, 1) -> will not return extra column
            - "GEOBL1" (Bundesländer, 16)
            - "GEOBL3" (Bundesländer, 16)
            - "GEOGM1" (Gemeinden, 11340)
            - "GEOGM2" (Gemeinden mit min. 10_000 Einwohnern, 1574)
            - "GEOGM3" (Gemeinden mit min. 10_000 Einwohnern, 1574)
            - "GEOLK1" (Landkreise und kreisfreie Städte, 412)
            - "GEOLK3" (Landkreise und kreisfreie Städte, 412)
            - "GEORB1" (Regierungsbezirke/Statistische Regionen, 36)
            - "GEORB3" (Regierungsbezirke/Statistische Regionen, 36)
            - "GEOVB1" (Gemeindeverbände, 1333)
            - "GEOVB2" (Gemeindeverbände mit mindestens 10 000 Einwohnern, 338)
            - "GEOVB3" (Gemeindeverbände mit mindestens 10 000 Einwohnern, 157)
    regionalkey (str, optional): Official municipality key (AGS).
        Multiple values can be passed as a comma-separated list.
        Accepts 1-12 characters. "*" can be used as wildcard.
    stand (str, optional): Only download the table if it is newer than the status date.
        "tt.mm.jjjj hh:mm" or "tt.mm.jjjj". Example: "24.12.2001 19:15".
    language (str, optional): Messages and data descriptions are supplied in this language.
    quality (bool, optional): If True, Value-adding quality labels are issued.
File:      c:\users\mdick\documents\github\pystatis\src\pystatis\table.py
Type:      method

prettify

prettify is a boolean and can only be True or False. The default is True because prettify is basically doing all the above mentioned work behind the scenes to transform the raw data into the nicer tidy version. However, as we don’t know what specific requirements you have, it can always be the case that we are not doing what you want to do or we are doing it in a wrong way. Instead of starting from scratch with the raw string, prettify=False will still give you a pandas DataFrame but without the transformations described in the previous sections. Basically, prettify=False gives you the raw data as a pandas DataFrame instead of a string without any transformation from our side.

[13]:
t = Table("1000A-0000")
t.get_data(prettify=False)
t.data.head(3)
INFO:pystatis.http_helper:Code 0: erfolgreich
[13]:
statistics_code statistics_label time_code time_label time 1_variable_code 1_variable_label 1_variable_attribute_code 1_variable_attribute_label value value_unit value_variable_code value_variable_label
0 1000A Bevölkerung kompakt (Gebietsstand 15.05.2022) STAG Stichtag 2022-05-15 GEOGM4 Gemeinden (Gebietsstand 15.05.2022) 092760130130 Lindberg 2294 Anzahl PRS018 Personen
1 1000A Bevölkerung kompakt (Gebietsstand 15.05.2022) STAG Stichtag 2022-05-15 GEOGM4 Gemeinden (Gebietsstand 15.05.2022) 073355011022 Landstuhl, Sickingenstadt, Stadt 8305 Anzahl PRS018 Personen
2 1000A Bevölkerung kompakt (Gebietsstand 15.05.2022) STAG Stichtag 2022-05-15 GEOGM4 Gemeinden (Gebietsstand 15.05.2022) 130765654053 Grebs-Niendorf 546 Anzahl PRS018 Personen
[18]:
# don't be confused by the query, we have to query by ARS in this example because prettify=True sorts the data by ARS and the order is different from above
t = Table("1000A-0000")
t.get_data(prettify=True)
t.data[t.data["Amtlicher Regionalschlüssel (ARS)"].isin(["092760130130", "073355011022", "130765654053"])]
INFO:pystatis.http_helper:Code 0: erfolgreich
[18]:
Stichtag Amtlicher Regionalschlüssel (ARS) Gemeinden (Gebietsstand 15.05.2022) Personen__Anzahl
4816 2022-05-15 073355011022 Landstuhl, Sickingenstadt, Stadt 8305
6934 2022-05-15 092760130130 Lindberg 2294
9394 2022-05-15 130765654053 Grebs-Niendorf 546
[19]:
t.data.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 10787 entries, 0 to 10786
Data columns (total 4 columns):
 #   Column                               Non-Null Count  Dtype
---  ------                               --------------  -----
 0   Stichtag                             10787 non-null  object
 1   Amtlicher Regionalschlüssel (ARS)    10787 non-null  object
 2   Gemeinden (Gebietsstand 15.05.2022)  10787 non-null  object
 3   Personen__Anzahl                     10787 non-null  int64
dtypes: int64(1), object(3)
memory usage: 337.2+ KB

area

We don’t have a good explanation for this one, so if you have a concrete use case, please let us know!

Here is the description from the official documentation:

The area query parameter specifies the area in which the object is stored, which is analogous to online navigation. Here is the breakdown:

For internal users:

  • Meine/Benutzer

  • Gruppe

  • Amt

  • Katalog/Öffentlich

  • Alle

For external users:

  • Meine/Benutzer

  • Katalog/Öffentlich

This parameter corresponds to:

  • Bereich=Benutzer as Bereich=Meine

  • Bereich=Öffentlich as Bereich=Katalog

startyear, endyear and timeslices

All three parameters can be used to fetch data of a certain time range for the given Table. The default is Table specific and has to be checked for each Table, often it is just the latest period of time available.

The important thing here is that timeslices is cumulative to the other two options, meaning that timeslices=N will give you N years after startyear or before endyear.

Let’s say you are interested in school-leaving qualifications over the years in Germany. Then Table 21111-0004 might be of interest to you. The description of the table mentions that data is available for the years 1997/98 - 2021/22. But what will the API return if you specify no time parameter?

[7]:
t = Table("21111-0004")
t.get_data()
t.data["Schuljahr"].unique()
INFO:pystatis.cache:Data was successfully cached under /Users/miay/.pystatis/data/21111-0004/7f787b175d83ae25ee55/20240630.csv.
INFO:pystatis.http_helper:Code 0: erfolgreich
[7]:
array(['2020/21', '2021/22'], dtype=object)

As you can see, pystatis only returns you, for whatever reason, the years 2020/21 and 2021/22. How can you get the ten latest years? Let’s see:

[8]:
t.get_data(timeslices=10)
t.data["Schuljahr"].unique()
INFO:pystatis.cache:Data was successfully cached under /Users/miay/.pystatis/data/21111-0004/188b2885044566b1329d/20240630.csv.
INFO:pystatis.http_helper:Code 0: erfolgreich
[8]:
array(['2012/13', '2013/14', '2014/15', '2015/16', '2016/17', '2017/18',
       '2018/19', '2019/20', '2020/21', '2021/22'], dtype=object)
[9]:
t.get_data(startyear="2012")
t.data["Schuljahr"].unique()
INFO:pystatis.cache:Data was successfully cached under /Users/miay/.pystatis/data/21111-0004/2cd6fefd6a6c423b70bd/20240630.csv.
INFO:pystatis.http_helper:Code 0: erfolgreich
[9]:
array(['2012/13', '2013/14', '2014/15', '2015/16', '2016/17', '2017/18',
       '2018/19', '2019/20', '2020/21', '2021/22'], dtype=object)

If you are only interested in a time period somewhere in between, you need to use both startyear and endyear:

[11]:
t.get_data(startyear="2012", endyear="2015")
t.data["Schuljahr"].unique()
INFO:pystatis.cache:Data was successfully cached under /Users/miay/.pystatis/data/21111-0004/23e95897ca6a80fd2617/20240630.csv.
INFO:pystatis.http_helper:Code 0: erfolgreich
[11]:
array(['2012/13', '2013/14', '2014/15', '2015/16'], dtype=object)

You might expect that using startyear and timeslices might give the same result, but it turns out that this is not the case and quite misleading. In fact, timeslices is always coming on top of whatever you have selected with startyear and endyear. Is that confusing? We definitely think so!

[13]:
t.get_data(startyear="2012", endyear="2015", timeslices=3)  # gives everything between 2012 and 2015 three more years
t.data["Schuljahr"].unique()
INFO:pystatis.cache:Data was successfully cached under /Users/miay/.pystatis/data/21111-0004/3286f8f1af46f895cd26/20240630.csv.
INFO:pystatis.http_helper:Code 0: erfolgreich
[13]:
array(['2012/13', '2013/14', '2014/15', '2015/16', '2019/20', '2020/21',
       '2021/22'], dtype=object)
[14]:
t.get_data(endyear="2015", timeslices=3)  # gives everything up to 2015 and three more years
t.data["Schuljahr"].unique()
INFO:pystatis.cache:Data was successfully cached under /Users/miay/.pystatis/data/21111-0004/6e1a814d2cac7d1233f1/20240630.csv.
INFO:pystatis.http_helper:Code 0: erfolgreich
[14]:
array(['1997/98', '1998/99', '1999/00', '2000/01', '2001/02', '2002/03',
       '2003/04', '2004/05', '2005/06', '2006/07', '2007/08', '2008/09',
       '2009/10', '2010/11', '2011/12', '2012/13', '2013/14', '2014/15',
       '2015/16', '2019/20', '2020/21', '2021/22'], dtype=object)

regionalvariable and regionalkey

Tables that end with a “B” in Regionalstatistik are special: They allow to change the regional depth of the data, meaning that you can fetch data for different regional areas depending on these two variables. The same is true for all Zensus tables.

To select a specific region area, you can either specify regionalvariable and pass one of the reserved codes for this geo variable, or you can directly select a specific region via its key. Let’s see some examples, so let’s analyze Table 12613-01-01-5-B:

[2]:
t = Table("12613-01-01-5-B")
t.get_data()
t.data.head(5)
INFO:pystatis.http_helper:Code 0: erfolgreich
[2]:
Jahr Amtlicher Gemeindeschlüssel (AGS) Gemeinden Geschlecht Gestorbene__Anzahl
0 2022 01001000 Flensburg, kreisfreie Stadt Insgesamt 1200.0
1 2022 01001000 Flensburg, kreisfreie Stadt männlich 594.0
2 2022 01001000 Flensburg, kreisfreie Stadt weiblich 606.0
3 2022 01002000 Kiel, kreisfreie Stadt, Landeshauptstadt Insgesamt 2996.0
4 2022 01002000 Kiel, kreisfreie Stadt, Landeshauptstadt männlich 1479.0

Instead of fetching the data for all municipalities, we can choose a different regional depth (see the codes here), for example “KRESIE”, one level above “GEMEINDE”, which is the default for this table.

[2]:
t = Table("12613-01-01-5-B")
t.get_data(regionalvariable="KREISE")
t.data.head(5)
INFO:pystatis.http_helper:Code 0: erfolgreich
[2]:
Jahr Amtlicher Gemeindeschlüssel (AGS) Kreise und kreisfreie Städte Geschlecht Gestorbene__Anzahl
0 2022 01001 Flensburg, kreisfreie Stadt Insgesamt 1200.0
1 2022 01001 Flensburg, kreisfreie Stadt männlich 594.0
2 2022 01001 Flensburg, kreisfreie Stadt weiblich 606.0
3 2022 01002 Kiel, kreisfreie Stadt Insgesamt 2996.0
4 2022 01002 Kiel, kreisfreie Stadt männlich 1479.0

regionalkey can be used to fetch only certain areas, see https://datengui.de/statistik-erklaert/ags. We now fetch only municipalities in Baden-Württemberg:

[3]:
t = Table("12613-01-01-5-B")
t.get_data(regionalkey="08*")
t.data.head(5)
INFO:pystatis.http_helper:Code 0: erfolgreich
[3]:
Jahr Amtlicher Gemeindeschlüssel (AGS) Gemeinden Geschlecht Gestorbene__Anzahl
0 2022 08111000 Stuttgart, Landeshauptstadt Insgesamt NaN
1 2022 08111000 Stuttgart, Landeshauptstadt männlich NaN
2 2022 08111000 Stuttgart, Landeshauptstadt weiblich NaN
3 2022 08115001 Aidlingen Insgesamt NaN
4 2022 08115001 Aidlingen männlich NaN

stand

Can be used to only download tables that have a version newer than the given date.

[4]:
t = Table("21111-0004")
t.get_data()
t.data.head(5)
INFO:pystatis.http_helper:Code 0: erfolgreich
[4]:
Schuljahr Deutschland insgesamt Geschlecht Schulart Schulabschlüsse Absolventen_und_Abgaenger__Anzahl
0 2020/21 Deutschland männlich Hauptschulen Ohne Hauptschulabschluss 4086.0
1 2020/21 Deutschland männlich Hauptschulen Hauptschulabschluss 22784.0
2 2020/21 Deutschland männlich Hauptschulen Mittlerer Schulabschluss 12700.0
3 2020/21 Deutschland männlich Hauptschulen Fachhochschulreife NaN
4 2020/21 Deutschland männlich Hauptschulen Allgemeine Hochschulreife NaN
[5]:
t.metadata["Object"]["Updated"]
[5]:
'24.11.2023 14:49:25h'
[6]:
t.get_data(stand="01.01.2023")  # before updated date, so should return data
t.data.head()
INFO:pystatis.http_helper:Code 0: erfolgreich
[6]:
Schuljahr Deutschland insgesamt Geschlecht Schulart Schulabschlüsse Absolventen_und_Abgaenger__Anzahl
0 2020/21 Deutschland männlich Hauptschulen Ohne Hauptschulabschluss 4086.0
1 2020/21 Deutschland männlich Hauptschulen Hauptschulabschluss 22784.0
2 2020/21 Deutschland männlich Hauptschulen Mittlerer Schulabschluss 12700.0
3 2020/21 Deutschland männlich Hauptschulen Fachhochschulreife NaN
4 2020/21 Deutschland männlich Hauptschulen Allgemeine Hochschulreife NaN
[7]:
t.get_data(stand="01.01.2024")  # after updated date, so error
t.data.head()
---------------------------------------------------------------------------
NoNewerDataError                          Traceback (most recent call last)
Cell In[7], line 1
----> 1 t.get_data(stand="01.01.2024") # after updated date, so error
      2 t.data.head()

File ~/git/github/CorrelAid/pystatis/src/pystatis/table.py:118, in Table.get_data(self, prettify, area, startyear, endyear, timeslices, regionalvariable, regionalkey, stand, language, quality)
    115 db_matches = db.identify_db_matches(self.name)
    116 db_name = db.select_db_by_credentials(db_matches)
--> 118 raw_data_bytes = load_data(endpoint="data", method="tablefile", params=params, db_name=db_name)
    119 assert isinstance(raw_data_bytes, bytes)  # nosec assert_used
    120 raw_data_str = raw_data_bytes.decode("utf-8-sig")

File ~/git/github/CorrelAid/pystatis/src/pystatis/http_helper.py:51, in load_data(endpoint, method, params, db_name)
     49     data = read_from_cache(cache_dir, name, params)
     50 else:
---> 51     response = get_data_from_endpoint(endpoint, method, params, db_name)
     52     content_type = response.headers.get("Content-Type", "text/csv").split("/")[-1]
     53     data = response.content

File ~/git/github/CorrelAid/pystatis/src/pystatis/http_helper.py:124, in get_data_from_endpoint(endpoint, method, params, db_name)
    122 response.encoding = "UTF-8"
    123 _check_invalid_status_code(response)
--> 124 _check_invalid_destatis_status_code(response)
    126 return response

File ~/git/github/CorrelAid/pystatis/src/pystatis/http_helper.py:266, in _check_invalid_destatis_status_code(response)
    263     response_dict = None
    265 if response_dict is not None:
--> 266     _check_destatis_status(response_dict.get("Status", {}))

File ~/git/github/CorrelAid/pystatis/src/pystatis/http_helper.py:305, in _check_destatis_status(destatis_status)
    303     pass
    304 elif destatis_status_code == 50:
--> 305     raise NoNewerDataError(destatis_status_content) from None
    306 else:
    307     raise DestatisStatusError(destatis_status_content) from None

NoNewerDataError: Keine aktualisierten Daten vorhanden. (Mindestens ein Parameter enthält ungültige Werte. Er wurde angepasst, um den Service starten zu können.: stand)

language

language can either be “de” or “en, with “de” being the default, obviously. Regionalstatistik is not supporting “en” and will not translate any data, Genesis and Zensus have some support for English, but you have to check for yourself, if the data is translated and to what extend.

[9]:
t = Table("81000-0001")
t.get_data()
t.data.head(1)
INFO:pystatis.http_helper:Code 0: erfolgreich
[9]:
Jahr Deutschland insgesamt Preisbasis Bruttowertschoepfung__jew._ME Guetersteuern_abzuegl._Guetersubventionen__jew._ME Guetersteuern__jew._ME Guetersubventionen__jew._ME Bruttoinlandsprodukt__jew._ME nachr.:_Bruttoinlandsprodukt_(Veraenderung_in_%)__Prozent nachr.:_Bruttoinlandsprodukt_je_Einwohner__jew._ME
0 2014 Deutschland in jeweiligen Preisen (Mrd. EUR) 2635.393 292.037 298.774 6.737 2927.43 4.1 36149.0
[11]:
t = Table("81000-0001")
t.get_data(language="en")
t.data.head(1)
INFO:pystatis.http_helper:Code 0: successfull
[11]:
Year Germany Price base Gross_value_added__jew._ME Taxes_on_products_less_subsidies__jew._ME Taxes_on_products__jew._ME Subsidies_on_products__jew._ME Gross_domestic_product__jew._ME Mem._item:_Gross_domestic_product_(change_in_%)__percent Mem._item:_Gross_domestic_product_per_inhabitant__jew._ME
0 2014 Germany At current prices (bn EUR) 2635.393 292.037 298.774 6.737 2927.43 4.1 36149.0

quality

quality can be either “on” or “off”, with “off” being the default. When switching to “on”, the downloaded table has additional quality columns “__q” for each value column with quality symbols. Check Explanation of symbols Not supported for all tables or databases.

[15]:
t = Table("52111-0001")
t.get_data(quality="on")
t.data.head(1)
INFO:pystatis.http_helper:Code 0: erfolgreich
[15]:
Jahr Deutschland insgesamt Beschäftigtengrößenklassen WZ2008 (Abschnitte): URS Unternehmen_(EU)__Anzahl Unternehmen_(EU)__q
0 2021 Deutschland 0 bis unter 10 abhängig Beschäftigte Bergbau und Gewinnung von Steinen und Erden 1065 e
[16]:
t = Table("12211-Z-11")
t.get_data(quality="on")  # not supported, ignored, but also no warning
t.data.head(1)
INFO:pystatis.http_helper:Code 0: erfolgreich
[16]:
Jahr Amtlicher Gemeindeschlüssel (AGS) Kreise und kreisfreie Städte Art der Lebensform Lebensformen_am_Hauptwohnort__1000
0 2019 DG Deutschland Insgesamt 42059.0
[20]:
t = Table("1000A-0000")
t.get_data(quality="on")
t.data.head(1)
INFO:pystatis.cache:Data was successfully cached under /Users/miay/.pystatis/data/1000A-0000/ec488574ddc014f6340b/20240713.zip.
INFO:pystatis.http_helper:Code 0: erfolgreich
[20]:
Stichtag Amtlicher Regionalschlüssel (ARS) Gemeinden (Gebietsstand 15.05.2022) Personen__Anzahl Personen__Anzahl__q
0 2022-05-15 DG Deutschland 82719540 e