Dorm room accessibility in German cities

import matplotlib.pyplot as plt # number_of_citizens, student_percentage, min_dorm_rental_fee, max_dorm_rental_fee, dorm_rooms_available (Source: CHE Hochschulranking, https://ranking.zeit.de/che/de/orte) university_cities = { 'Aachen': (243336, 22.4, 123, 550, 4855), 'Aalen': (67344, 8.6, 215, 405, 1875), 'Albstadt': (44431, 4.5, 169, 390, 5594), 'Alfter': (23153, 6.1, -1, -1, -1), 'Amberg': (41535, 4.5, 125, 274, 2293), 'Ansbach': (40010, 7.3, 159, 319, 3706), 'Aschaffenburg': (68167, 4.9, 194, 386, 3733), 'Augsburg': (281111, 9.2, 190, 374, 2018), 'Bad Homburg': (52752, 1.1, -1, -1, -1), 'Bad Honnef': (25078, 30.7, -1, -1, -1), 'Bad Sooden-Allendorf': (8350, 8.5, -1, -1, -1), 'Bamberg': (71952, 17.5, 194, 386, 3733), 'Bautzen': (39845, -1, -1, -1, -1), 'Bayreuth': (71601, 18.1, 125, 274, 2293), 'Benediktbeuern': (3563, 17.1, -1, -1, -1), 'Berlin': (3469849, 5.1, 120, 380, 9378), 'Bernburg': (33633, 10.1, 186, 293, 3370), 'Biberach an der Riss': (32233, 7.4, 215, 405, 1875), 'Bielefeld': (329782, 11.2, 167, 345, 2671), 'Bingen': (24987, 10.5, 297, 412, 4261), 'Birkenfeld': (6883, 36.7, -1, -1, -1), 'Bocholt': (70837, 2.8, 209, 492, 4116), 'Bochum': (361876, 15.7, 209, 492, 4116), 'Bonn': (313958, 11.8, 172, 560, 3733), 'Bottrop': (116017, 1.0, -1, -1, -1), 'Brandenburg': (71032, 3.7, 140, 435, 2946), 'Braunschweig': (248502, 8.2, 159, 620, 4665), 'Bremen': (551767, 6.0, 188, 282, 1922), 'Bremerhaven': (110121, 2.9, 188, 282, 1922), 'Bruehl': (43995, 4.6, -1, -1, -1), 'Buxtehude': (39792, 2.4, 159, 620, 4665), 'Calw': (23232, 1.3, -1, -1, -1), 'Chemnitz': (248645, 4.6, 157, 260, 2765), 'Clausthal': (15769, 31.2, 159, 620, 4665), 'Coburg': (41062, 12.6, 125, 274, 2293), 'Cottbus': (99491, 6.8, 158, 389, 3799), 'Darmstadt': (151879, 30.8, 182, 562, 2539), 'Deggendorf': (31886, 18.3, 167, 456, 2445), 'Dessau': (83061, 1.6, 186, 293, 3370), 'Detmold': (73586, 3.6, 167, 345, 2671), 'Dieburg': (15192, 19.2, -1, -1, -1), 'Diepholz': (16169, 1.6, -1, -1, -1), 'Dornbirn (A)': (48152, -1, -1, -1, -1), 'Dortmund': (580511, 8.8, 181, 250, 2873), 'Dresden': (543825, 8.1, 101, 370, 6753), 'Duisburg': (485465, -1, 215, 370, 2404), 'Düsseldorf': (604527, 8.1, 230, 375, 3800), 'Eberswalde': (38897, 5.5, 158, 389, 3799), 'Eichstätt': (13300, 32.0, -1, -1, -1), 'Elmshorn': (47907, 3.8, -1, -1, -1), 'Elsfleth': (9040, 5.9, 155, 345, 2060), 'Emden': (50016, 8.5, 155, 345, 2060), 'Erfurt': (210118, 4.7, 105, 332, 7191), 'Erlangen': (106423, 27.7, 159, 319, 3706), 'Essen': (573784, -1, 215, 370, 2404), 'Esslingen': (91271, 5.3, 200, 389, 6755), 'Feldkirchen (A)': (14238, -1, -1, -1, -1), 'Flensburg': (84694, 10.9, 151, 439, 3036), 'Frankfurt am Main': (717624, 8.9, 206, 480, 2788), 'Frankfurt/Oder': (57649, 11.3, 158, 389, 3799), 'Freiberg': (41641, 11.5, 160, 370, 1485), 'Freiburg i. Br.': (226393, 14.6, 196, 398, 4648), 'Freis.-Weihenst.': (45857, 8.8, 177, 427, 10615), 'Friedberg': (27859, 20.3, 159, 446, 3022), 'Friedrichshafen': (59108, 6.2, 228, 420, 2950), 'Fulda': (65540, 12.3, 159, 446, 3022), 'Fuerth': (121519, 0.1, -1, -1, -1), 'Furtwangen': (9091, 40.2, 196, 398, 4648), 'Garching': (16456, -1, -1, -1, -1), 'Geislingen': (5910, 36.1, 166, 393, 5667), 'Gelsenkirchen': (257651, 2.3, 209, 492, 4116), 'Gengenbach': (10941, -1, -1, -1, -1), 'Gera': (96011, 1.0, 105, 332, 7191), 'Giessen': (83280, 45.5, 159, 446, 3022), 'Glauchau': (23255, -1, -1, -1, -1), 'Göppingen': (56781, 2.2, 200, 389, 6755), 'Görlitz': (55255, 2.7, 101, 370, 6753), 'Göttingen': (117665, 29.4, 140, 390, 4454), 'Graz (A)': (286686, -1, -1, -1, -1), 'Greifswald': (56685, 19.2, 137, 311, 1644), 'Gummersbach': (49734, 10.0, 137, 347, 4732), 'Gütersloh': (96085, 0.0, -1, -1, -1), 'Hagen': (186716, 2.3, 181, 250, 2873), 'Hagenberg (A)': (2727, -1, -1, -1, -1), 'Halle (Saale)': (232470, 8.8, 186, 293, 3370), 'Hamburg': (1762791, 5.2, 233, 415, 3946), 'Hameln': (56310, 0.9, -1, -1, -1), 'Hamm': (176580, 1.7, 215, 470, 1512), 'Hannover': (523642, 8.6, 149, 343, 2258), 'Heide': (21303, 7.4, 151, 439, 3036), 'Heidelberg': (156267, 24.1, 162, 363, 5384), 'Heilbronn': (122567, 7.5, 162, 363, 5384), 'Heiligenhaus': (25474, 1.1, -1, -1, -1), 'Hildesheim': (99979, 10.5, 159, 620, 4665), 'Hof': (44325, 10.6, 125, 274, 2293), 'Höhr-Grenzhausen': (9346, 1.9, -1, -1, -1), 'Holzminden': (20169, 6.4, -1, -1, -1), 'Homburg/Saar': (41974, -1, 181, 276, 1115), 'Höxter': (29388, 3.3, -1, -1, -1), 'Idstein': (23801, 7.7, -1, -1, -1), 'Ilmenau': (26153, 25.3, 105, 332, 7191), 'Ingolstadt': (131002, 4.8, 159, 319, 3706), 'Innsbruck (A)': (131009, -1, -1, -1, -1), 'Iserlohn': (92899, 4.9, 181, 250, 2873), 'Isny im Allgäu': (13602, 1.2, -1, -1, -1), 'Jena': (109527, 20.4, 105, 332, 7191), 'Jülich': (32247, 11.7, 123, 550, 4855), 'Kaiserslautern': (98520, 17.2, 140, 350, 2042), 'Kamp-Lintfort': (37118, 4.5, 230, 375, 3800), 'Kapfenberg': (23067, -1, -1, -1, -1), 'Karlsruhe': (307755, 14.6, 157, 362, 2786), 'Kassel': (194747, 14.5, 165, 420, 1087), 'Kempten': (65624, 9.0, 190, 374, 2018), 'Kiel': (243148, 13.7, 151, 439, 3036), 'Klagenfurt (A)': (99997, -1, -1, -1, -1), 'Kleve': (48802, 8.8, 230, 375, 3800), 'Koblenz': (112586, 12.5, 215, 326, 526), 'Köln': (1046680, 9.4, 137, 347, 4732), 'Konstanz': (82859, 19.9, 228, 420, 2950), 'Köthen': (26384, 10.0, 186, 293, 3370), 'Krefeld': (222500, 2.9, 230, 375, 3800), 'Krems (A)': (24418, -1, -1, -1, -1), 'Kufstein (A)': (18727, -1, -1, -1, -1), 'Künzelsau': (15127, 10.0, -1, -1, -1), 'Landau': (45362, 17.0, 145, 300, 984), 'Landshut': (67509, 8.0, 167, 456, 2445), 'Leer': (33925, 1.2, -1, -1, -1), 'Leipzig': (560472, 6.6, 138, 425, 5264), 'Lemgo': (40709, 9.1, -1, -1, -1), 'Leverkusen': (161540, 0.4, -1, -1, -1), 'Lingen/Ems': (52503, 4.3, 150, 401, 1782), 'Lippstadt': (66518, 3.1, 215, 470, 1512), 'Lübeck': (214420, 4.3, 151, 439, 3036), 'Ludwigsburg': (92973, 9.9, 200, 389, 6755), 'Ludwigshafen': (164718, 2.7, 145, 300, 984), 'Lüneburg': (72546, 12.6, 159, 620, 4665), 'Magdeburg': (232306, 8.0, 154, 299, 1652), 'Mainz': (209779, 18.0, 297, 412, 4216), 'Mannheim': (305780, 10.7, 190, 410, 3173), 'Marburg': (73147, 36.0, 156, 316, 1889), 'Merseburg': (33317, 9.0, 186, 293, 3370), 'Meschede': (30002, 17.8, -1, -1, -1), 'Minden': (80212, 2.0, 145, 394, 2671), 'Mittweida': (14939, 47.2, 160, 370, 1485), 'Mönchengladbach': (256853, 3.1, 230, 375, 3800), 'Мülheim an der Ruhr': (167108, 2.1, 215, 370, 2404), 'München': (1429584, 8.3, 177, 427, 10615), 'Münster': (302178, 18.8, 170, 595, 5636), 'Neubrandenburg': (63311, 3.2, 137, 311, 1644), 'Neunkirchen': (46369, -1, -1, -1, -1), 'Neuss': (152644, 0.6, -1, -1, -1), 'Neu-Ulm': (55689, 6.7, 190, 374, 2018), 'Nordhausen': (42217, 5.5, 105, 332, 7191), 'Nürnberg': (501072, 4.9, 159, 319, 3706), 'Nürtingen': (40535, 8.2, 166, 393, 5667), 'Oestrich-Winkel': (11524, 14.4, -1, -1, -1), 'Offenburg': (58465, 7.8, 196, 398, 4648), 'Oldenburg': (160907, 10.1, 155, 345, 2060), 'Osnabrück': (156897, 15.7, 150, 401, 1782), 'Paderborn': (145176, 14.9, 215, 470, 1512), 'Passau': (49952, 23.7, 167, 456, 2445), 'Pforzheim': (122247, 5.0, 157, 362, 2786), 'Pirmasens': (40125, 1.7, 140, 350, 2042), 'Plauen': (65201, -1, -1, -1, -1), 'Potsdam': (164042, 15.0, 140, 435, 2946), 'Pulheim': (53345, 0.2, -1, -1, -1), 'Recklinghausen': (114147, 2.0, -1, -1, -1), 'Regensburg': (142292, 22.1, 167, 456, 2445), 'Reichenbach': (21200, 0.2, -1, -1, -1), 'Remagen': (16392, 17.6, 215, 326, 526), 'Reutlingen': (114310, 5.1, 166, 393, 5667), 'Rheinbach': (26852, 8.5, 172, 560, 3733), 'Riedlingen': (10451, -1, -1, -1, -1), 'Riesa': (30885, -1, -1, -1, -1), 'Rödermark': (26881, -1, -1, -1, -1), 'Rosenheim': (60889, 9.7, 177, 427, 10615), 'Rostock': (204167, 7.0, 114, 420, 2293), 'Rüsselsheim': (61967, 5.4, 206, 480, 2786), 'Saarbrücken': (178151, 17.3, 181, 276, 1115), 'Salzgitter': (98966, 2.5, -1, -1, -1), 'Sankt Augustin': (54631, 9.7, 172, 560, 3733), 'Schmalkalden': (19291, 14.6, 105, 332, 7191), 'Schwäbisch Hall': (38827, 2.5, -1, -1, -1), 'Schweinfurt': (51610, 6.1, 194, 386, 3733), 'Schwerin': (92318, -1, -1, -1, -1), 'Senftenberg': (24743, 6.0, 158, 389, 3799), 'Siegen': (100325, 20.0, 186, 426, 940), 'Sigmaringen': (18271, 8.0, 266, 393, 5667), 'Soest': (46925, 6.2, 188, 250, 2873), 'Spittal an der Drau (A)': (15542, -1, -1, -1, -1), 'Stade': (45772, -1, -1, -1, -1), 'Steinfurt': (33225, 14.2, 170, 595, 5636), 'Stendal': (40079, 5.2, -1, -1, -1), 'Steyr (A)': (38347, -1, -1, -1, -1), 'St. Pölten (A)': (53629, -1, -1, -1, -1), 'Stralsund': (57525, 3.9, 137, 311, 1644), 'Sttugart': (623738, 8.9, 200, 389, 6755), 'Suderburg': (4533, 31.7, 159, 620, 4665), 'Trier': (114914, 16.7, 173, 307, 1617), 'Тübingen': (87464, 32.0, 166, 393, 5667), 'Tulln an der Donau (A)': (16038, -1, -1, -1, -1), 'Tuttlingen': (34586, 1.8, -1, -1, -1), 'Ulm': (122636, 12.0, 215, 405, 1875), 'Vallendar': (88502, 16.8, -1, -1, -1), 'Vechta': (31352, 17.6, 150, 401, 1782), 'Villach (A)': (61218, -1, -1, -1, -1), 'Villingen-Schwenningen': (84674, 10.8, 196, 398, 4648), 'Warburg': (23290, -1, -1, -1, -1), 'Wedel': (32574, 3.6, 151, 439, 3036), 'Weiden': (41817, 3.8, 125, 274, 2293), 'Weidenbach': (2190, 98.3, -1, -1, -1), 'Weimar': (64131, 7.6, 105, 332, 7191), 'Weingarten': (24460, 13.4, 228, 420, 2950), 'Wels (A)': (64870, -1, -1, -1, -1), 'Wernigerode': (33319, 6.6, 154, 299, 1652), 'Wetzlar': (51262, 2.4, -1, -1, -1), 'Wien (A)': (1840226, -1, -1, -1, -1), 'Wiener Neustadt (A)': (48775, -1, -1, -1, -1), 'Wiesbaden': (275116, 3.8, 206, 480, 2788), 'Wieselburg (A)': (4012, -1, -1, -1, -1), 'Wildau': (9945, 40.7, 140, 435, 2946), 'Wilhelmshaven': (75534, 6.2, 155, 345, 2060), 'Wismar': (42392, 20.6, 114, 420, 2293), 'Witten': (95907, 2.3, -1, -1, -1), 'Wolfenbüttel': (51670, 11.1, 159, 620, 4665), 'Wolfsburg': (123027, 2.7, 159, 620, 4665), 'Worms': (82102, 4.2, 145, 300, 984), 'Wuppertal': (345425, 6.2, 190, 326, 1085), 'Würzburg': (124219, 27.9, 194, 386, 3733), 'Zittau': (25712, 5.6, 101, 370, 6753), 'Zweibrücken': (34260, 7.6, 140, 350, 2042), 'Zwickau': (91123, 4.8, 157, 260, 2765) } def rank(city_data): number_of_citizens, student_percentage, min_dorm_rental_fee, max_dorm_rental_fee, dorm_rooms_available = city_data number_students = number_of_citizens / student_percentage avg_rooms_per_student = dorm_rooms_available / number_students min_avg_rental_fee_per_room = min_dorm_rental_fee / avg_rooms_per_student max_avg_rental_fee_per_room = max_dorm_rental_fee / avg_rooms_per_student # "Higher is better" is more intuitive. Swap sides to have range values in sorted order. return (1/max_avg_rental_fee_per_room, 1/min_avg_rental_fee_per_room) rest, ranked = {}, {} max_citizens, max_rent, max_rooms = -1, -1, -1 display_cities = 50 fontsize = 9 hadjust, vadjust = -3, 0.18 k = 0 for k, v in university_cities.items(): if -1 not in (v[1], v[-1]): if v[0] > max_citizens: max_citizens = v[0] if v[3] > max_rent: max_rent = v[3] if v[4] > max_rooms: max_rooms = v[4] rest[k] = v num_cities = len(rest) for k, v in rest.items(): ranked[k] = rank(( v[0] / max_citizens, v[1] / 100, v[2] / max_rent, v[3] / max_rent, v[4] / max_rooms )) ranked_sorted = sorted(ranked.items(), key = lambda x: x[1][0], reverse=True)[:display_cities] plt.figure(figsize=(7,10)) for city, index_range in ranked_sorted[::-1]: plt.plot(index_range, (k+vadjust, k+vadjust), color='#777777', lw=3) plt.text(hadjust, k, city, fontsize=fontsize, horizontalalignment='right') k += 1 plt.title('Which German cities offer the best access to dorm rooms for students?') plt.xlim(-0.5, 450) plt.ylim(-0.5, display_cities) plt.xlabel('index value') plt.yticks([]) plt.show() Index of the accessibility of dorm rooms in German cities

Notice that some cities were excluded, because the data about them was incomplete. Only the first 50 cities are shown and we notice that these are primarily small ones. According to this data, Geislingen, has relatively few students, but its Studentenwerk offers lots of rooms, which are also relatively low-priced (166-393 €). This improves the accessibility of the rooms to students and allows them to focus more fully on the studying process instead of constantly worrying about finding a highly paid job to cover the costs. The disadvantage then, of course, is that finding a job in such a small city, if it is needed, will be quite hard. Other small cities with very good chances to find a more accessible dorm room include Suderburg, Furtwangen, Wildau, Ilmenau, Schmalkalden, Clausthal and Mittweida.

If you prefer slightly bigger cities, Kaiserslautern, Darmstadt, Heilbronn, Mainz, Regensburg, Aachen, Trier, Potsdam or Erfurt might be interesting to you.

According to this self-made index, Hamburg appears at the last place, which is interesting. It's a large city, but the available rooms relative to the number of students seeking rooms and the rooms provided by the Studentenwerk and the prices at which they are available leaves something to be desired. Only Hamm divides Berlin from Hamburg. Other big cities with very low index include Wuppertal, Frankfurt/Main, Wiesbaden, Bremen, Gelsenkirchen, Hannover, Nürnberg, Köln, Düsseldorf, München, Wolfsburg, Dortmund, Augsburg, Koblenz, Rostock. Slightly higher ranked are Stuttgart, Dresden and Karlsruhe (change the value of display_cities to see that).

The ability to easily find a room that is not too expensive is only one side of being a student in an unknown city. It is exactly as important, when not even more, that the university you apply at has exactly the specialty you are looking for, with a good reputation in your specific field. Additionally, the job opportunities are very different in each city, so you may want to find additional data about the number of existing jobs and the average salaries, incorporating it too and running the computation once again. Additionally, if you know exactly what you want to work in advance, look for average data only across this smaller set of choices. You probably risk a lot if you go to a city that will force you to work something you dislike, shaping your carreer far away from your desired direction or leaving you stuck and unhappy. Certain cities may appreciate your knowledge and skills much more than others, for the same type of work. This is a question of priorities and the strength of the existing guilds there.

Personally, I spent time in Ulm and Koblenz, but this was a long time ago. Before making my choice I was neither good at programming, nor data analysis. One thing that has always been important to me is that the city offers exactly the opportunity I am looking for. Because if it doesn't, it's probably more appropriate to look elsewhere. Or create the opportunities yourself.