DataFrame

Playing Pandas

The underlying idea of a DataFrame is based on spreadsheets. We can see the data structure of a DataFrame as tabular and spreadsheet-like. A DataFrame logically corresponds to a "sheet" of an Excel document. A DataFrame has both a row and a column index.

Like a spreadsheet or Excel sheet, a DataFrame object contains an ordered collection of columns. Each column consists of a unique data typye, but different columns can have different types, e.g. the first column may consist of integers, while the second one consists of boolean values and so on.

There is a close connection between the DataFrames and the Series of Pandas. A DataFrame can be seen as a concatenation of Series, each Series having the same index, i.e. the index of the DataFrame.

We will demonstrate this in the following example.

We define the following three Series:

import pandas as pd

years = range(2014, 2018)

shop1 = pd.Series([2409.14, 2941.01, 3496.83, 3119.55], index=years)
shop2 = pd.Series([1203.45, 3441.62, 3007.83, 3619.53], index=years)
shop3 = pd.Series([3412.12, 3491.16, 3457.19, 1963.10], index=years)

What happens, if we concatenate these "shop" Series? Pandas provides a concat function for this purpose:

pd.concat([shop1, shop2, shop3])
Output:
2014    2409.14
2015    2941.01
2016    3496.83
2017    3119.55
2014    1203.45
2015    3441.62
2016    3007.83
2017    3619.53
2014    3412.12
2015    3491.16
2016    3457.19
2017    1963.10
dtype: float64

This result is not what we have intended or expected. The reason is that concat used 0 as the default for the axis parameter. Let's do it with "axis=1":

shops_df = pd.concat([shop1, shop2, shop3], axis=1)
shops_df
Output:
0 1 2
2014 2409.14 1203.45 3412.12
2015 2941.01 3441.62 3491.16
2016 3496.83 3007.83 3457.19
2017 3119.55 3619.53 1963.10

Let's do some fine sanding by giving names to the columns:

cities = ["Zürich", "Winterthur", "Freiburg"]
shops_df.columns = cities 
print(shops_df)

# alternative way: give names to series:
shop1.name = "Zürich"
shop2.name = "Winterthur"
shop3.name = "Freiburg"

print("------")
shops_df2 = pd.concat([shop1, shop2, shop3], axis=1)
print(shops_df2)
       Zürich  Winterthur  Freiburg
2014  2409.14     1203.45   3412.12
2015  2941.01     3441.62   3491.16
2016  3496.83     3007.83   3457.19
2017  3119.55     3619.53   1963.10
------
       Zürich  Winterthur  Freiburg
2014  2409.14     1203.45   3412.12
2015  2941.01     3441.62   3491.16
2016  3496.83     3007.83   3457.19
2017  3119.55     3619.53   1963.10

This was nice, but what kind of data type is our result?

print(type(shops_df))
<class 'pandas.core.frame.DataFrame'>

This means, we can arrange or concat Series into DataFrames!

DataFrames from Dictionaries

A DataFrame has a row and column index; it's like a dict of Series with a common index.

cities = {"name": ["London", "Berlin", "Madrid", "Rome", 
                   "Paris", "Vienna", "Bucharest", "Hamburg", 
                   "Budapest", "Warsaw", "Barcelona", 
                   "Munich", "Milan"],
          "population": [8615246, 3562166, 3165235, 2874038,
                         2273305, 1805681, 1803425, 1760433,
                         1754000, 1740119, 1602386, 1493900,
                         1350680],
          "country": ["England", "Germany", "Spain", "Italy",
                      "France", "Austria", "Romania", 
                      "Germany", "Hungary", "Poland", "Spain",
                      "Germany", "Italy"]}

city_frame = pd.DataFrame(cities)
city_frame
Output:
name population country
0 London 8615246 England
1 Berlin 3562166 Germany
2 Madrid 3165235 Spain
3 Rome 2874038 Italy
4 Paris 2273305 France
5 Vienna 1805681 Austria
6 Bucharest 1803425 Romania
7 Hamburg 1760433 Germany
8 Budapest 1754000 Hungary
9 Warsaw 1740119 Poland
10 Barcelona 1602386 Spain
11 Munich 1493900 Germany
12 Milan 1350680 Italy

Retrieving the Column Names

It's possible to get the names of the columns as a list:

city_frame.columns.values
Output:
array(['name', 'population', 'country'], dtype=object)

Custom Index

We can see that an index (0,1,2, ...) has been automatically assigned to the DataFrame. We can also assign a custom index to the DataFrame object:

ordinals = ["first", "second", "third", "fourth",
            "fifth", "sixth", "seventh", "eigth",
            "ninth", "tenth", "eleventh", "twelvth",
            "thirteenth"]
city_frame = pd.DataFrame(cities, index=ordinals)
city_frame
Output:
name population country
first London 8615246 England
second Berlin 3562166 Germany
third Madrid 3165235 Spain
fourth Rome 2874038 Italy
fifth Paris 2273305 France
sixth Vienna 1805681 Austria
seventh Bucharest 1803425 Romania
eigth Hamburg 1760433 Germany
ninth Budapest 1754000 Hungary
tenth Warsaw 1740119 Poland
eleventh Barcelona 1602386 Spain
twelvth Munich 1493900 Germany
thirteenth Milan 1350680 Italy

Rearranging the Order of Columns

We can also define and rearrange the order of the columns at the time of creation of the DataFrame. This makes also sure that we will have a defined ordering of our columns, if we create the DataFrame from a dictionary. Dictionaries are not ordered, as you have seen in our chapter on Dictionaries in our Python tutorial, so we cannot know in advance what the ordering of our columns will be:

city_frame = pd.DataFrame(cities,
                          columns=["name", 
                                   "country", 
                                   "population"])
city_frame
Output:
name country population
0 London England 8615246
1 Berlin Germany 3562166
2 Madrid Spain 3165235
3 Rome Italy 2874038
4 Paris France 2273305
5 Vienna Austria 1805681
6 Bucharest Romania 1803425
7 Hamburg Germany 1760433
8 Budapest Hungary 1754000
9 Warsaw Poland 1740119
10 Barcelona Spain 1602386
11 Munich Germany 1493900
12 Milan Italy 1350680

We change both the column order and the ordering of the index with the function reindex with the following code:

city_frame.reindex(index=[0, 2, 4, 6,  8, 10, 12, 1, 3, 5, 7, 9, 11], 
                   columns=['country', 'name', 'population'])
Output:
country name population
0 England London 8615246
2 Spain Madrid 3165235
4 France Paris 2273305
6 Romania Bucharest 1803425
8 Hungary Budapest 1754000
10 Spain Barcelona 1602386
12 Italy Milan 1350680
1 Germany Berlin 3562166
3 Italy Rome 2874038
5 Austria Vienna 1805681
7 Germany Hamburg 1760433
9 Poland Warsaw 1740119
11 Germany Munich 1493900

Now, we want to rename our columns. For this purpose, we will use the DataFrame method 'rename'. This method supports two calling conventions

  • (index=index_mapper, columns=columns_mapper, ...)
  • (mapper, axis={'index', 'columns'}, ...)

We will rename the columns of our DataFrame into Romanian names in the following example. We set the parameter inplace to True so that our DataFrame will be changed instead of returning a new DataFrame, if inplace is set to False, which is the default!

city_frame.rename(columns={"name":"Soyadı", 
                           "country":"Ülke", 
                           "population":"Nüfus"},
                 inplace=True)
city_frame
Output:
Soyadı Ülke Nüfus
0 London England 8615246
1 Berlin Germany 3562166
2 Madrid Spain 3165235
3 Rome Italy 2874038
4 Paris France 2273305
5 Vienna Austria 1805681
6 Bucharest Romania 1803425
7 Hamburg Germany 1760433
8 Budapest Hungary 1754000
9 Warsaw Poland 1740119
10 Barcelona Spain 1602386
11 Munich Germany 1493900
12 Milan Italy 1350680

Existing Column as the Index of a DataFrame

We want to create a more useful index in the following example. We will use the country name as the index, i.e. the list value associated to the key "country" of our cities dictionary:

city_frame = pd.DataFrame(cities,
                          columns=["name", "population"],
                          index=cities["country"])

city_frame
Output:
name population
England London 8615246
Germany Berlin 3562166
Spain Madrid 3165235
Italy Rome 2874038
France Paris 2273305
Austria Vienna 1805681
Romania Bucharest 1803425
Germany Hamburg 1760433
Hungary Budapest 1754000
Poland Warsaw 1740119
Spain Barcelona 1602386
Germany Munich 1493900
Italy Milan 1350680

Alternatively, we can change an existing DataFrame. We can us the method set_index to turn a column into an index. "set_index" does not work in-place, it returns a new data frame with the chosen column as the index:

city_frame = pd.DataFrame(cities)
city_frame2 = city_frame.set_index("country")
print(city_frame2)
              name  population
country                       
England     London     8615246
Germany     Berlin     3562166
Spain       Madrid     3165235
Italy         Rome     2874038
France       Paris     2273305
Austria     Vienna     1805681
Romania  Bucharest     1803425
Germany    Hamburg     1760433
Hungary   Budapest     1754000
Poland      Warsaw     1740119
Spain    Barcelona     1602386
Germany     Munich     1493900
Italy        Milan     1350680

We saw in the previous example that the set_index method returns a new DataFrame object and doesn't change the original DataFrame. If we set the optional parameter "inplace" to True, the DataFrame will be changed in place, i.e. no new object will be created:

city_frame = pd.DataFrame(cities)
city_frame.set_index("country", inplace=True)
print(city_frame)
              name  population
country                       
England     London     8615246
Germany     Berlin     3562166
Spain       Madrid     3165235
Italy         Rome     2874038
France       Paris     2273305
Austria     Vienna     1805681
Romania  Bucharest     1803425
Germany    Hamburg     1760433
Hungary   Budapest     1754000
Poland      Warsaw     1740119
Spain    Barcelona     1602386
Germany     Munich     1493900
Italy        Milan     1350680

Accessing Rows via Index Values

So far we have accessed DataFrames via the columns. It is often necessary to select certain rows via the index names. We will demonstrate now, how we can access rows from DataFrames via the locators 'loc' and 'iloc'. We will not cover 'ix' because it is deprecated and will be removed in the future.

We select all the German cities in the following example by using 'loc'. The result is a DataFrame:

city_frame = pd.DataFrame(cities, 
                          columns=("name", "population"), 
                          index=cities["country"])
print(city_frame.loc["Germany"])
            name  population
Germany   Berlin     3562166
Germany  Hamburg     1760433
Germany   Munich     1493900

It is also possible to simultaneously extracting rows by chosen more than on index labels. To do this we use a list of indices:

print(city_frame.loc[["Germany", "France"]])
            name  population
Germany   Berlin     3562166
Germany  Hamburg     1760433
Germany   Munich     1493900
France     Paris     2273305

We will also need to select pandas DataFrame rows based on conditions, which are applied to column values. We can use the operators '>', '=', '=', '<=', '!=' for this purpose. We select all cities with a population of more than two million in the following example:

condition = city_frame.population>2000000
condition
Output:
England     True
Germany     True
Spain       True
Italy       True
France      True
Austria    False
Romania    False
Germany    False
Hungary    False
Poland     False
Spain      False
Germany    False
Italy      False
Name: population, dtype: bool

We can use this Boolean DataFrame condition with locto finally create the selection:

print(city_frame.loc[condition])
           name  population
England  London     8615246
Germany  Berlin     3562166
Spain    Madrid     3165235
Italy      Rome     2874038
France    Paris     2273305

It is also possible to logically combine more than one condition with & and |:

condition1 = (city_frame.population>1500000)
condition2 = (city_frame['name'].str.contains("m"))
print(city_frame.loc[condition1 & condition2])
            name  population
Italy       Rome     2874038
Germany  Hamburg     1760433

We use a logical or | in the following example to see all cities of the Pandas DataFrame, where either the city name contains the letter 'm' or the population number is greater than three million:

condition1 = (city_frame.population>3000000)
condition2 = (city_frame['name'].str.contains("m"))
print(city_frame.loc[condition1 | condition2])
            name  population
England   London     8615246
Germany   Berlin     3562166
Spain     Madrid     3165235
Italy       Rome     2874038
Germany  Hamburg     1760433

Adding Rows to a DataFrame

milan = ['Milan', 1399860]
city_frame.iloc[-1] = milan
city_frame.loc['Switzerland'] = ['Zurich', 415215]
city_frame
Output:
name population
England London 8615246
Germany Berlin 3562166
Spain Madrid 3165235
Italy Rome 2874038
France Paris 2273305
Austria Vienna 1805681
Romania Bucharest 1803425
Germany Hamburg 1760433
Hungary Budapest 1754000
Poland Warsaw 1740119
Spain Barcelona 1602386
Germany Munich 1493900
Italy Milan 1399860
Switzerland Zurich 415215

Accessing Rows by Position

The iloc method of a Pandas DataFrame object can be used to select rows and columns by number, i.e. in the order that they appear in the data frame. iloc allows selections of the rows, as if they were numbered by integers 0, 1, 2, ....

We demonstrate this in the following example:

df = city_frame.iloc[3]
print(df)
name             Rome
population    2874038
Name: Italy, dtype: object

To get a DataFrame with selected rows by numbers, we use a list of integers. We can see that we can change the order of the rows and we are also able to select rows multiple times:

df = city_frame.iloc[[3, 2, 0, 5, 0]]
print(df)
           name  population
Italy      Rome     2874038
Spain    Madrid     3165235
England  London     8615246
Austria  Vienna     1805681
England  London     8615246

Sum and Cumulative Sum

The DataFrame object of Pandas provides a method to sum both columns and rows. Before we will explain the usage of the sum method, we will create a new DataFrame object on which we will apply our examples. We will start by creating an empty DataFrame without columns but an index. We populate this DataFrame by adding columns with random values:

years = range(2014, 2019)
cities = ["Zürich", "Freiburg", "München", "Konstanz", "Saarbrücken"]
shops = pd.DataFrame(index=years)
for city in cities:
    shops.insert(loc=len(shops.columns),
                 column=city,
                 value=(np.random.uniform(0.7, 1, (5,)) * 1000).round(2))
    
print(shops)
      Zürich  Freiburg  München  Konstanz  Saarbrücken
2014  872.51    838.22   961.17    934.99       796.42
2015  944.47    943.27   862.66    784.23       770.94
2016  963.22    859.97   818.13    965.38       995.74
2017  866.11    731.42   811.37    955.21       836.36
2018  790.95    837.39   941.92    735.93       837.23

Let's apply sum to the DataFrame shops:

shops.sum()
Output:
Zürich         4504.85
Freiburg       4182.09
München        3999.67
Konstanz       4557.86
Saarbrücken    4608.05
dtype: float64

We can see that it summed up all the columns of our DataFrame. What about calculating the sum of the rows? We can do this by using the axis parameter of sum.

shops.sum(axis=1)
Output:
2014    4226.30
2015    4458.91
2016    4696.46
2017    4186.20
2018    4284.65
dtype: float64

You only want to the the sums for the first, third and the last column and for all the years:

s = shops.iloc[:, [0, 2, -1]]
print(s)
print("and now the sum:")
print(s.sum())
      Zürich  München  Saarbrücken
2014  780.38   952.88       854.93
2015  968.05   807.03       894.87
2016  990.00   803.41       991.15
2017  815.45   734.82       950.40
2018  950.97   701.53       916.70
and now the sum:
Zürich         4504.85
München        3999.67
Saarbrücken    4608.05
dtype: float64

Of course, you could have also have achieved it in the following way, if the column names are known:

shops[["Zürich", "München", "Saarbrücken"]].sum()
Output:
Zürich         4504.85
München        3999.67
Saarbrücken    4608.05
dtype: float64

We can use "cumsum" to calculate the cumulative sum over the years:

x = shops.cumsum()
print(x)
       Zürich  Freiburg  München  Konstanz  Saarbrücken
2014   780.38    908.77   952.88    729.34       854.93
2015  1748.43   1719.42  1759.91   1707.65      1749.80
2016  2738.43   2698.64  2563.32   2640.33      2740.95
2017  3553.88   3424.87  3298.14   3599.63      3691.35
2018  4504.85   4182.09  3999.67   4557.86      4608.05

Using the keyword parameter axis with the value 1, we can build the cumulative sum over the rows:

x = shops.cumsum(axis=1)
print(x)
      Zürich  Freiburg  München  Konstanz  Saarbrücken
2014  780.38   1689.15  2642.03   3371.37      4226.30
2015  968.05   1778.70  2585.73   3564.04      4458.91
2016  990.00   1969.22  2772.63   3705.31      4696.46
2017  815.45   1541.68  2276.50   3235.80      4186.20
2018  950.97   1708.19  2409.72   3367.95      4284.65

Assigning New Values to Columns

x is a Pandas Series. We can reassign the previously calculated cumulative sums to the population column:

city_frame["population"] = x
print(city_frame)
              name  population
England     London     8615246
Germany     Berlin    12177412
Spain       Madrid    15342647
Italy         Rome    18216685
France       Paris    20489990
Austria     Vienna    22295671
Romania  Bucharest    24099096
Germany    Hamburg    25859529
Hungary   Budapest    27613529
Poland      Warsaw    29353648
Spain    Barcelona    30956034
Germany     Munich    32449934
Italy        Milan    33800614

Instead of replacing the values of the population column with the cumulative sum, we want to add the cumulative population sum as a new culumn with the name "cum_population".

city_frame = pd.DataFrame(cities,
                          columns=["country", 
                                   "population",
                                   "cum_population"],
                          index=cities["name"])

city_frame
Output:
country population cum_population
London England 8615246 NaN
Berlin Germany 3562166 NaN
Madrid Spain 3165235 NaN
Rome Italy 2874038 NaN
Paris France 2273305 NaN
Vienna Austria 1805681 NaN
Bucharest Romania 1803425 NaN
Hamburg Germany 1760433 NaN
Budapest Hungary 1754000 NaN
Warsaw Poland 1740119 NaN
Barcelona Spain 1602386 NaN
Munich Germany 1493900 NaN
Milan Italy 1350680 NaN

We can see that the column "cum_population" is set to Nan, as we haven't provided any data for it.

We will assign now the cumulative sums to this column:

city_frame["cum_population"] = city_frame["population"].cumsum()
city_frame
Output:
country population cum_population
London England 8615246 8615246
Berlin Germany 3562166 12177412
Madrid Spain 3165235 15342647
Rome Italy 2874038 18216685
Paris France 2273305 20489990
Vienna Austria 1805681 22295671
Bucharest Romania 1803425 24099096
Hamburg Germany 1760433 25859529
Budapest Hungary 1754000 27613529
Warsaw Poland 1740119 29353648
Barcelona Spain 1602386 30956034
Munich Germany 1493900 32449934
Milan Italy 1350680 33800614

We can also include a column name which is not contained in the dictionary, when we create the DataFrame from the dictionary. In this case, all the values of this column will be set to NaN:

city_frame = pd.DataFrame(cities,
                          columns=["country", 
                                   "area",
                                   "population"],
                          index=cities["name"])
print(city_frame)
           country area  population
London     England  NaN     8615246
Berlin     Germany  NaN     3562166
Madrid       Spain  NaN     3165235
Rome         Italy  NaN     2874038
Paris       France  NaN     2273305
Vienna     Austria  NaN     1805681
Bucharest  Romania  NaN     1803425
Hamburg    Germany  NaN     1760433
Budapest   Hungary  NaN     1754000
Warsaw      Poland  NaN     1740119
Barcelona    Spain  NaN     1602386
Munich     Germany  NaN     1493900
Milan        Italy  NaN     1350680

Accessing the Columns of a DataFrame

There are two ways to access a column of a DataFrame. The result is in both cases a Series:

# in a dictionary-like way:
print(city_frame["population"])
London       8615246
Berlin       3562166
Madrid       3165235
Rome         2874038
Paris        2273305
Vienna       1805681
Bucharest    1803425
Hamburg      1760433
Budapest     1754000
Warsaw       1740119
Barcelona    1602386
Munich       1493900
Milan        1350680
Name: population, dtype: int64
# as an attribute
print(city_frame.population)
London       8615246
Berlin       3562166
Madrid       3165235
Rome         2874038
Paris        2273305
Vienna       1805681
Bucharest    1803425
Hamburg      1760433
Budapest     1754000
Warsaw       1740119
Barcelona    1602386
Munich       1493900
Milan        1350680
Name: population, dtype: int64
print(type(city_frame.population))
<class 'pandas.core.series.Series'>
city_frame.population
Output:
London       8615246
Berlin       3562166
Madrid       3165235
Rome         2874038
Paris        2273305
Vienna       1805681
Bucharest    1803425
Hamburg      1760433
Budapest     1754000
Warsaw       1740119
Barcelona    1602386
Munich       1493900
Milan        1350680
Name: population, dtype: int64

From the previous example, we can see that we have not copied the population column. "p" is a view on the data of city_frame.

Assigning New Values to a Column

The column area is still not defined. We can set all elements of the column to the same value:

city_frame["area"] = 1572
print(city_frame)
           country  area  population
London     England  1572     8615246
Berlin     Germany  1572     3562166
Madrid       Spain  1572     3165235
Rome         Italy  1572     2874038
Paris       France  1572     2273305
Vienna     Austria  1572     1805681
Bucharest  Romania  1572     1803425
Hamburg    Germany  1572     1760433
Budapest   Hungary  1572     1754000
Warsaw      Poland  1572     1740119
Barcelona    Spain  1572     1602386
Munich     Germany  1572     1493900
Milan        Italy  1572     1350680

In this case, it will be definitely better to assign the exact area to the cities. The list with the area values needs to have the same length as the number of rows in our DataFrame.

# area in square km:
area = [1572, 891.85, 605.77, 1285, 
        105.4, 414.6, 228, 755, 
        525.2, 517, 101.9, 310.4, 
        181.8]
# area could have been designed as a list, a Series, an array or a scalar   

city_frame["area"] = area
print(city_frame)
           country     area  population
London     England  1572.00     8615246
Berlin     Germany   891.85     3562166
Madrid       Spain   605.77     3165235
Rome         Italy  1285.00     2874038
Paris       France   105.40     2273305
Vienna     Austria   414.60     1805681
Bucharest  Romania   228.00     1803425
Hamburg    Germany   755.00     1760433
Budapest   Hungary   525.20     1754000
Warsaw      Poland   517.00     1740119
Barcelona    Spain   101.90     1602386
Munich     Germany   310.40     1493900
Milan        Italy   181.80     1350680

Sorting DataFrames

Let's sort our DataFrame according to the city area:

city_frame = city_frame.sort_values(by="area", ascending=False)
print(city_frame)
           country     area  population
London     England  1572.00     8615246
Rome         Italy  1285.00     2874038
Berlin     Germany   891.85     3562166
Hamburg    Germany   755.00     1760433
Madrid       Spain   605.77     3165235
Budapest   Hungary   525.20     1754000
Warsaw      Poland   517.00     1740119
Vienna     Austria   414.60     1805681
Munich     Germany   310.40     1493900
Bucharest  Romania   228.00     1803425
Milan        Italy   181.80     1350680
Paris       France   105.40     2273305
Barcelona    Spain   101.90     1602386

Let's assume, we have only the areas of London, Hamburg and Milan. The areas are in a series with the correct indices. We can assign this series as well:

city_frame = pd.DataFrame(cities,
                          columns=["country", 
                                   "area",
                                   "population"],
                          index=cities["name"])

some_areas = pd.Series([1572, 755, 181.8], 
                    index=['London', 'Hamburg', 'Milan'])

city_frame['area'] = some_areas
print(city_frame)
           country    area  population
London     England  1572.0     8615246
Berlin     Germany     NaN     3562166
Madrid       Spain     NaN     3165235
Rome         Italy     NaN     2874038
Paris       France     NaN     2273305
Vienna     Austria     NaN     1805681
Bucharest  Romania     NaN     1803425
Hamburg    Germany   755.0     1760433
Budapest   Hungary     NaN     1754000
Warsaw      Poland     NaN     1740119
Barcelona    Spain     NaN     1602386
Munich     Germany     NaN     1493900
Milan        Italy   181.8     1350680

Inserting new columns into existing DataFrames

In the previous example we have added the column area at creation time. Quite often it will be necessary to add or insert columns into existing DataFrames. For this purpose the DataFrame class provides a method "insert", which allows us to insert a column into a DataFrame at a specified location:

insert(self, loc, column, value, allow_duplicates=False)`

The parameters are specified as:

Parameter Meaning
loc int
This value should be within
the range 0 <= loc <= len(columns)
column the column name
value can be a list, a Series an array or a scalar
allow_duplicates If allow_duplicates is False,
an Exception will be raised,
if column is already contained
in the DataFrame.
city_frame = pd.DataFrame(cities,
                          columns=["country", 
                                   "population"],
                          index=cities["name"])


idx = 1
city_frame.insert(loc=idx, column='area', value=area)
city_frame
Output:
country area population
London England 1572.00 8615246
Berlin Germany 891.85 3562166
Madrid Spain 605.77 3165235
Rome Italy 1285.00 2874038
Paris France 105.40 2273305
Vienna Austria 414.60 1805681
Bucharest Romania 228.00 1803425
Hamburg Germany 755.00 1760433
Budapest Hungary 525.20 1754000
Warsaw Poland 517.00 1740119
Barcelona Spain 101.90 1602386
Munich Germany 310.40 1493900
Milan Italy 181.80 1350680

Creating a DataFrame by appending Rows

import pandas as pd
from numpy.random import randint

df = pd.DataFrame(columns=['lib', 'qty1', 'qty2'])
for i in range(5):
     df.loc[i] = ['name' + str(i)] + list(randint(10, size=2))
    
df
Output:
lib qty1 qty2
0 name0 1 8
1 name1 5 6
2 name2 9 9
3 name3 8 8
4 name4 7 0

DataFrame from Nested Dictionaries

A nested dictionary of dicts can be passed to a DataFrame as well. The indices of the outer dictionary are taken as the the columns and the inner keys. i.e. the keys of the nested dictionaries, are used as the row indices:

growth = {"Switzerland": {"2010": 3.0, "2011": 1.8, "2012": 1.1, "2013": 1.9},
          "Germany": {"2010": 4.1, "2011": 3.6, "2012":	0.4, "2013": 0.1},
          "France": {"2010":2.0,  "2011":2.1, "2012": 0.3, "2013": 0.3},
          "Greece": {"2010":-5.4, "2011":-8.9, "2012":-6.6, "2013":	-3.3},
          "Italy": {"2010":1.7, "2011":	0.6, "2012":-2.3, "2013":-1.9}
          } 
growth_frame = pd.DataFrame(growth)
growth_frame
Output:
Switzerland Germany France Greece Italy
2010 3.0 4.1 2.0 -5.4 1.7
2011 1.8 3.6 2.1 -8.9 0.6
2012 1.1 0.4 0.3 -6.6 -2.3
2013 1.9 0.1 0.3 -3.3 -1.9

You like to have the years in the columns and the countries in the rows? No problem, you can transpose the data:

growth_frame.T
Output:
2010 2011 2012 2013
Switzerland 3.0 1.8 1.1 1.9
Germany 4.1 3.6 0.4 0.1
France 2.0 2.1 0.3 0.3
Greece -5.4 -8.9 -6.6 -3.3
Italy 1.7 0.6 -2.3 -1.9
growth_frame = growth_frame.T

growth_frame2 = growth_frame.reindex(["Switzerland", 
                                      "Italy", 
                                      "Germany", 
                                      "Greece"])
print(growth_frame2)
             2010  2011  2012  2013
Switzerland   3.0   1.8   1.1   1.9
Italy         1.7   0.6  -2.3  -1.9
Germany       4.1   3.6   0.4   0.1
Greece       -5.4  -8.9  -6.6  -3.3

Filling a DataFrame with random values:

import numpy as np

names = ['Frank', 'Eve', 'Stella', 'Guido', 'Lara']
index = ["January", "February", "March",
         "April", "May", "June",
         "July", "August", "September",
         "October", "November", "December"]
df = pd.DataFrame((np.random.randn(12, 5)*1000).round(2),
                  columns=names,
                  index=index)
df
Output:
Frank Eve Stella Guido Lara
January -2452.01 -91.03 -122.31 -750.05 931.99
February -874.08 -189.72 628.49 -392.53 342.06
March -1222.37 -1125.60 -826.90 -107.74 -831.32
April 1333.69 1468.56 -1537.82 -743.23 624.10
May 802.27 -1444.17 84.38 -376.80 256.64
June -762.07 207.63 -476.06 -2068.54 -1614.25
July -1172.28 -2582.39 -351.16 -555.88 -21.40
August -468.52 -665.97 833.53 -1650.37 -426.07
September -788.57 408.96 -652.73 346.99 875.78
October 92.81 699.84 251.47 872.04 415.53
November 558.65 -1699.90 -949.95 212.92 -1874.80
December -646.58 -35.22 -1018.20 -644.35 776.56