数据结构:DataFrames 对象

已完成

对于数据科学,Pandas 中还有一个需要了解的重要的数据结构是 DataFrame。 与 Series 对象一样,DataFrames 可被看作是 ndarrays 的泛化,或者看作是 Python 字典的专用化。

就像 Series 与具有灵活索引的一维数组类似一样,DataFrame 类似于具有灵活行索引和灵活列名称的二维数组。 DataFrame 表示数据的矩形表,包含标记列的有序集合,其中每个列都可以是不同的值类型(例如 stringintfloat)。 DataFrame 同时包含行索引和列索引。 你可将它看作是 Series 的字典,所有这些都共享同一索引。

让我们看看它的实际工作原理。 首先,创建一个名为 areaSeries

area_dict = {'Albania': 28748,
             'France': 643801,
             'Germany': 357386,
             'Japan': 377972,
             'Russia': 17125200}
area = pd.Series(area_dict)
area

输出为:

Albania       28748
France       643801
Germany      357386
Japan        377972
Russia     17125200
dtype: int64

现在,你可将它与之前创建的 populationSeries 组合起来。 使用字典构造单个二维表,其中包含这两个 Series 中的数据:

countries = pd.DataFrame({'Population': population, 'Area': area})
countries

输出为:

|          | Population   | Area      |
---------------------------------------
| Albania  | NaN          | 28748     |
| France   | 65429495.0   | 643801    |
| Germany  | 82408706.0   | 357386    |
| Japan    | 126922333.0  | 377972    |
| Russia   | 143910127.0  | 17125200  |

Series 一样,DataFrames 还会自动对索引进行排序(在本例中是列索引 Area 和 Population)

到目前为止,你已经将字典合组合起来构成一个 DataFrame(这使 DataFrame 以行为中心),但你也可按列方式创建 DataFrames。 请考虑使用可靠的旧数组模拟添加“首都/主要城市”列,列表:

countries['Capital/Major City'] = ['Tirana', 'Paris', 'Berlin', 'Tokyo', 'Moscow']
countries

输出为:

|          | Population   | Area      | Capital/Major City  |
-------------------------------------------------------------
| Albania  | NaN          | 28748     | Tirana              |
| France   | 65429495.0   | 643801    | Paris               |
| Germany  | 82408706.0   | 357386    | Berlin              |
| Japan    | 126922333.0  | 377972    | Tokyo               |
| Russia   | 143910127.0  | 17125200  | Moscow              |

Series 一样,即使初始索引按 DataFrames 进行排序,后续添加到 DataFrame 的内容仍按添加的顺序排序。 不过,你可通过这种方式显式更改 DataFrame 列索引的顺序:

countries = countries[['Capital/Major City', 'Area', 'Population']]
countries

输出为:

|          | Capital/Major City   | Area      | Population   |
--------------------------------------------------------------
| Albania  |  Tirana              | 28748     | NaN          | 
| France   |  Paris               | 643801    | 65429495.0   | 
| Germany  |  Berlin              | 357386    | 82408706.0   | 
| Japan    |  Tokyo               | 377972    | 126922333.0  | 
| Russia   |  Moscow              | 17125200  | 143910127.0  | 

通常在数据科学环境中,你需要从现有数据集生成新的数据列。 由于 DataFrame 列的行为与 Series 的类似,因此要实现这一点,可像操作 Series 一样来操作它们:

countries['Population Density'] = countries['Population'] / countries['Area']
countries

输出为:

|          | Capital/Major City   | Area      | Population   | Population density |
-----------------------------------------------------------------------------------
| Albania  |  Tirana              | 28748     | NaN          | NaN                |
| France   |  Paris               | 643801    | 65429495.0   | 101.629999         |
| Germany  |  Berlin              | 357386    | 82408706.0   | 230.587393         |
| Japan    |  Tokyo               | 377972    | 126922333.0  | 335.798242         |
| Russia   |  Moscow              | 17125200  | 143910127.0  | 8.403413           |

注意

如果 IPython 对此发出警告,请不要担心。 此警告表示 IPython 尝试提供的帮助有点过多。 你创建的新列是 DataFrame 的实际部分,不是切片的副本。

我们曾说过 DataFrames 就像字典一样。 你可检索列的内容,就像在普通字典中检索特定键的值一样:

countries['Area']

输出为:

Albania       28748
France       643801
Germany      357386
Japan        377972
Russia     17125200
Name: Area, dtype: int64

如果使用行索引,会怎么样呢?

现在,请尝试使用类似 countries['Japan'] 的命令访问行数据。

此操作会返回错误。 DataFramesSeries 的字典,它们是列。 DataFrame 行通常具有异类数据类型,因此需要用其他方法来访问行数据。 为此,我们使用 .loc 方法:

countries.loc['Japan']

输出为:

Capital/Major City                     Tokyo
Area                                  377972
Population                       1.26922e+08
Population Density                   335.798
Name: Japan, dtype: object

请注意,.loc 方法返回的内容是其自身的索引对象,你可使用常用的索引语法来访问其中的元素:

countries.loc['Japan']['Area']

输出为:

377972

你能想到如何不使用 .iloc 方法来返回日本区域吗?

提示

首先尝试放置列索引。

你是否也能对这些索引进行切片?

有时在数据科学项目中,将列添加到 DataFrame 很有帮助,无需为其赋值:

countries['Debt-to-GDP Ratio'] = np.nan
countries

输出为:

|          | Capital/Major City   | Area      | Population   | Population density | Debt-to-GDP ratio |
-------------------------------------------------------------------------------------------------------
| Albania  |  Tirana              | 28748     | NaN          | NaN                | NaN               |
| France   |  Paris               | 643801    | 65429495.0   | 101.629999         | NaN               |
| Germany  |  Berlin              | 357386    | 82408706.0   | 230.587393         | NaN               |
| Japan    |  Tokyo               | 377972    | 126922333.0  | 335.798242         | NaN               |
| Russia   |  Moscow              | 17125200  | 143910127.0  | 8.403413           | NaN               |

同样,你可忽略任何有关以这种方式添加列的警告。

你还可将列添加到 DataFrame,后者的行数与 DataFrame 不同:

debt = pd.Series([0.19, 2.36], index=['Russia', 'Japan'])
countries['Debt-to-GDP Ratio'] = debt
countries

输出为:

|          | Capital/Major City   | Area      | Population   | Population density | Debt-to-GDP ratio |
-------------------------------------------------------------------------------------------------------
| Albania  |  Tirana              | 28748     | NaN          | NaN                | NaN               |
| France   |  Paris               | 643801    | 65429495.0   | 101.629999         | NaN               |
| Germany  |  Berlin              | 357386    | 82408706.0   | 230.587393         | NaN               |
| Japan    |  Tokyo               | 377972    | 126922333.0  | 335.798242         | 2.36              |
| Russia   |  Moscow              | 17125200  | 143910127.0  | 8.403413           | 0.19              |

可使用 del 命令从 DataFrame 中删除列:

del countries['Capital']
countries

输出为:

|          | Area      | Population   | Population density | Debt-to-GDP ratio |
--------------------------------------------------------------------------------
| Albania  | 28748     | NaN          | NaN                | NaN               |
| France   | 643801    | 65429495.0   | 101.629999         | NaN               |
| Germany  | 357386    | 82408706.0   | 230.587393         | NaN               |
| Japan    | 377972    | 126922333.0  | 335.798242         | 2.36              |
| Russia   | 17125200  | 143910127.0  | 8.403413           | 0.19              |

除了类似字典的行为以外,DataFrames 的行为也类似于二维数组。 例如,在使用 DataFrame 时,可能需要将其转置:

countries.T

输出为:

|                     | Albania  | France        | Germany       | Japan         | Russia        |
--------------------------------------------------------------------------------------------------
| Area                | 28748.0  | 6.438010e+05  | 3.573860e+05  | 3.779720e+05  | 1.712520e+07  |
| Population          | NaN      | 6.542950e+07  | 8.240871e+07  | 1.269223e+08  | 1.439101e+08  |
| Population density  | NaN      | 1.016300e+02  | 2.305874e+02  | 3.357982e+02  | 8.403413e+00  |
| Debt-to-GDP ratio   | NaN      | NaN           | NaN           | 2.360000e+00  | 1.900000e-01  |

同样请注意,DataFrame 列都是 Series,因此数据类型必须一致。 这就是你看到向上转换为浮点数的原因。

重要说明

如果此 DataFrame 中存在字符串,则所有内容都会向上转换为 string 类型。 转置 DataFrames 时请小心。

从二维 NumPy 数组

给定数据的二维数组后,可使用任意指定的列和索引名称创建 DataFrame。 如果省略此项,将对以下每项使用整数索引:

pd.DataFrame(np.random.rand(3, 2),
             columns=['random', 'example'],
             index=['a', 'b', 'c'])

输出为:

|    | random       | example       |
------------------------------
| a  | 0.733086  | 0.708453  |
| b  | 0.722008  | 0.048097  |
| c  | 0.275534  | 0.822378  |