数据结构:DataFrames 对象
对于数据科学,Pandas 中还有一个需要了解的重要的数据结构是 DataFrame。 与 Series 对象一样,DataFrames 可被看作是 ndarrays 的泛化,或者看作是 Python 字典的专用化。
就像 Series 与具有灵活索引的一维数组类似一样,DataFrame 类似于具有灵活行索引和灵活列名称的二维数组。 DataFrame 表示数据的矩形表,包含标记列的有序集合,其中每个列都可以是不同的值类型(例如 string、int 或 float)。 DataFrame 同时包含行索引和列索引。 你可将它看作是 Series 的字典,所有这些都共享同一索引。
让我们看看它的实际工作原理。 首先,创建一个名为 area 的 Series:
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'] 的命令访问行数据。
此操作会返回错误。 DataFrames 是 Series 的字典,它们是列。 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 |