Pandas 2.2 中文官方教程和指南(四)(1)https://developer.aliyun.com/article/1509879
RIGHT JOIN
显示df2
中的所有记录。
SELECT * FROM df1 RIGHT OUTER JOIN df2 ON df1.key = df2.key;
In [30]: pd.merge(df1, df2, on="key", how="right") Out[30]: key value_x value_y 0 B -0.282863 1.212112 1 D -1.135632 -0.173215 2 D -1.135632 0.119209 3 E NaN -1.044236
FULL JOIN
pandas 还允许进行FULL JOIN
,它会显示数据集的两侧,无论连接列是否找到匹配。截至目前,不是所有的 RDBMS(MySQL)都支持FULL JOIN
。
显示两个表中的所有记录。
SELECT * FROM df1 FULL OUTER JOIN df2 ON df1.key = df2.key;
In [31]: pd.merge(df1, df2, on="key", how="outer") Out[31]: key value_x value_y 0 A 0.469112 NaN 1 B -0.282863 1.212112 2 C -1.509059 NaN 3 D -1.135632 -0.173215 4 D -1.135632 0.119209 5 E NaN -1.044236
INNER JOIN
SELECT * FROM df1 INNER JOIN df2 ON df1.key = df2.key;
# merge performs an INNER JOIN by default In [26]: pd.merge(df1, df2, on="key") Out[26]: key value_x value_y 0 B -0.282863 1.212112 1 D -1.135632 -0.173215 2 D -1.135632 0.119209
merge()
还提供参数,用于在您希望将一个数据框的列与另一个数据框的索引进行连接的情况。
In [27]: indexed_df2 = df2.set_index("key") In [28]: pd.merge(df1, indexed_df2, left_on="key", right_index=True) Out[28]: key value_x value_y 1 B -0.282863 1.212112 3 D -1.135632 -0.173215 3 D -1.135632 0.119209
LEFT OUTER JOIN
显示df1
中的所有记录。
SELECT * FROM df1 LEFT OUTER JOIN df2 ON df1.key = df2.key;
In [29]: pd.merge(df1, df2, on="key", how="left") Out[29]: key value_x value_y 0 A 0.469112 NaN 1 B -0.282863 1.212112 2 C -1.509059 NaN 3 D -1.135632 -0.173215 4 D -1.135632 0.119209
RIGHT JOIN
显示df2
中的所有记录。
SELECT * FROM df1 RIGHT OUTER JOIN df2 ON df1.key = df2.key;
In [30]: pd.merge(df1, df2, on="key", how="right") Out[30]: key value_x value_y 0 B -0.282863 1.212112 1 D -1.135632 -0.173215 2 D -1.135632 0.119209 3 E NaN -1.044236
FULL JOIN
pandas 还允许进行FULL JOIN
,它会显示数据集的两侧,无论连接列是否找到匹配。截至目前,不是所有的 RDBMS(MySQL)都支持FULL JOIN
。
显示两个表中的所有记录。
SELECT * FROM df1 FULL OUTER JOIN df2 ON df1.key = df2.key;
In [31]: pd.merge(df1, df2, on="key", how="outer") Out[31]: key value_x value_y 0 A 0.469112 NaN 1 B -0.282863 1.212112 2 C -1.509059 NaN 3 D -1.135632 -0.173215 4 D -1.135632 0.119209 5 E NaN -1.044236
UNION
可以使用concat()
执行UNION ALL
。
In [32]: df1 = pd.DataFrame( ....: {"city": ["Chicago", "San Francisco", "New York City"], "rank": range(1, 4)} ....: ) ....: In [33]: df2 = pd.DataFrame( ....: {"city": ["Chicago", "Boston", "Los Angeles"], "rank": [1, 4, 5]} ....: ) ....:
SELECT city, rank FROM df1 UNION ALL SELECT city, rank FROM df2; /* city rank Chicago 1 San Francisco 2 New York City 3 Chicago 1 Boston 4 Los Angeles 5 */
In [34]: pd.concat([df1, df2]) Out[34]: city rank 0 Chicago 1 1 San Francisco 2 2 New York City 3 0 Chicago 1 1 Boston 4 2 Los Angeles 5
SQL 的UNION
类似于UNION ALL
,但UNION
会删除重复行。
SELECT city, rank FROM df1 UNION SELECT city, rank FROM df2; -- notice that there is only one Chicago record this time /* city rank Chicago 1 San Francisco 2 New York City 3 Boston 4 Los Angeles 5 */
在 pandas 中,您可以结合使用 concat()
和 drop_duplicates()
。
In [35]: pd.concat([df1, df2]).drop_duplicates() Out[35]: city rank 0 Chicago 1 1 San Francisco 2 2 New York City 3 1 Boston 4 2 Los Angeles 5
限制
SELECT * FROM tips LIMIT 10;
In [36]: tips.head(10) Out[36]: total_bill tip sex smoker day time size 0 16.99 1.01 Female No Sun Dinner 2 1 10.34 1.66 Male No Sun Dinner 3 2 21.01 3.50 Male No Sun Dinner 3 3 23.68 3.31 Male No Sun Dinner 2 4 24.59 3.61 Female No Sun Dinner 4 5 25.29 4.71 Male No Sun Dinner 4 6 8.77 2.00 Male No Sun Dinner 2 7 26.88 3.12 Male No Sun Dinner 4 8 15.04 1.96 Male No Sun Dinner 2 9 14.78 3.23 Male No Sun Dinner 2
pandas 中一些 SQL 分析和聚合函数的等效函数
带有偏移的前 n 行
-- MySQL SELECT * FROM tips ORDER BY tip DESC LIMIT 10 OFFSET 5;
In [37]: tips.nlargest(10 + 5, columns="tip").tail(10) Out[37]: total_bill tip sex smoker day time size 183 23.17 6.50 Male Yes Sun Dinner 4 214 28.17 6.50 Female Yes Sat Dinner 3 47 32.40 6.00 Male No Sun Dinner 4 239 29.03 5.92 Male No Sat Dinner 3 88 24.71 5.85 Male No Thur Lunch 2 181 23.33 5.65 Male Yes Sun Dinner 2 44 30.40 5.60 Male No Sun Dinner 4 52 34.81 5.20 Female No Sun Dinner 4 85 34.83 5.17 Female No Thur Lunch 4 211 25.89 5.16 Male Yes Sat Dinner 4
每个组的前 n 行
-- Oracle's ROW_NUMBER() analytic function SELECT * FROM ( SELECT t.*, ROW_NUMBER() OVER(PARTITION BY day ORDER BY total_bill DESC) AS rn FROM tips t ) WHERE rn < 3 ORDER BY day, rn;
In [38]: ( ....: tips.assign( ....: rn=tips.sort_values(["total_bill"], ascending=False) ....: .groupby(["day"]) ....: .cumcount() ....: + 1 ....: ) ....: .query("rn < 3") ....: .sort_values(["day", "rn"]) ....: ) ....: Out[38]: total_bill tip sex smoker day time size rn 95 40.17 4.73 Male Yes Fri Dinner 4 1 90 28.97 3.00 Male Yes Fri Dinner 2 2 170 50.81 10.00 Male Yes Sat Dinner 3 1 212 48.33 9.00 Male No Sat Dinner 4 2 156 48.17 5.00 Male No Sun Dinner 6 1 182 45.35 3.50 Male Yes Sun Dinner 3 2 197 43.11 5.00 Female Yes Thur Lunch 4 1 142 41.19 5.00 Male No Thur Lunch 5 2
使用 rank(method='first')
函数相同
In [39]: ( ....: tips.assign( ....: rnk=tips.groupby(["day"])["total_bill"].rank( ....: method="first", ascending=False ....: ) ....: ) ....: .query("rnk < 3") ....: .sort_values(["day", "rnk"]) ....: ) ....: Out[39]: total_bill tip sex smoker day time size rnk 95 40.17 4.73 Male Yes Fri Dinner 4 1.0 90 28.97 3.00 Male Yes Fri Dinner 2 2.0 170 50.81 10.00 Male Yes Sat Dinner 3 1.0 212 48.33 9.00 Male No Sat Dinner 4 2.0 156 48.17 5.00 Male No Sun Dinner 6 1.0 182 45.35 3.50 Male Yes Sun Dinner 3 2.0 197 43.11 5.00 Female Yes Thur Lunch 4 1.0 142 41.19 5.00 Male No Thur Lunch 5 2.0
-- Oracle's RANK() analytic function SELECT * FROM ( SELECT t.*, RANK() OVER(PARTITION BY sex ORDER BY tip) AS rnk FROM tips t WHERE tip < 2 ) WHERE rnk < 3 ORDER BY sex, rnk;
让我们找到每个性别组中 (rank < 3) 的小费,对于 (tips < 2)。请注意,当使用 rank(method='min')
函数时,相同 tip
的 rnk_min
保持不变(类似于 Oracle 的 RANK()
函数)
In [40]: ( ....: tips[tips["tip"] < 2] ....: .assign(rnk_min=tips.groupby(["sex"])["tip"].rank(method="min")) ....: .query("rnk_min < 3") ....: .sort_values(["sex", "rnk_min"]) ....: ) ....: Out[40]: total_bill tip sex smoker day time size rnk_min 67 3.07 1.00 Female Yes Sat Dinner 1 1.0 92 5.75 1.00 Female Yes Fri Dinner 2 1.0 111 7.25 1.00 Female No Sat Dinner 1 1.0 236 12.60 1.00 Male Yes Sat Dinner 2 1.0 237 32.83 1.17 Male Yes Sat Dinner 2 2.0
带有偏移的前 n 行
-- MySQL SELECT * FROM tips ORDER BY tip DESC LIMIT 10 OFFSET 5;
In [37]: tips.nlargest(10 + 5, columns="tip").tail(10) Out[37]: total_bill tip sex smoker day time size 183 23.17 6.50 Male Yes Sun Dinner 4 214 28.17 6.50 Female Yes Sat Dinner 3 47 32.40 6.00 Male No Sun Dinner 4 239 29.03 5.92 Male No Sat Dinner 3 88 24.71 5.85 Male No Thur Lunch 2 181 23.33 5.65 Male Yes Sun Dinner 2 44 30.40 5.60 Male No Sun Dinner 4 52 34.81 5.20 Female No Sun Dinner 4 85 34.83 5.17 Female No Thur Lunch 4 211 25.89 5.16 Male Yes Sat Dinner 4
每个组的前 n 行
-- Oracle's ROW_NUMBER() analytic function SELECT * FROM ( SELECT t.*, ROW_NUMBER() OVER(PARTITION BY day ORDER BY total_bill DESC) AS rn FROM tips t ) WHERE rn < 3 ORDER BY day, rn;
In [38]: ( ....: tips.assign( ....: rn=tips.sort_values(["total_bill"], ascending=False) ....: .groupby(["day"]) ....: .cumcount() ....: + 1 ....: ) ....: .query("rn < 3") ....: .sort_values(["day", "rn"]) ....: ) ....: Out[38]: total_bill tip sex smoker day time size rn 95 40.17 4.73 Male Yes Fri Dinner 4 1 90 28.97 3.00 Male Yes Fri Dinner 2 2 170 50.81 10.00 Male Yes Sat Dinner 3 1 212 48.33 9.00 Male No Sat Dinner 4 2 156 48.17 5.00 Male No Sun Dinner 6 1 182 45.35 3.50 Male Yes Sun Dinner 3 2 197 43.11 5.00 Female Yes Thur Lunch 4 1 142 41.19 5.00 Male No Thur Lunch 5 2
使用 rank(method='first')
函数相同
In [39]: ( ....: tips.assign( ....: rnk=tips.groupby(["day"])["total_bill"].rank( ....: method="first", ascending=False ....: ) ....: ) ....: .query("rnk < 3") ....: .sort_values(["day", "rnk"]) ....: ) ....: Out[39]: total_bill tip sex smoker day time size rnk 95 40.17 4.73 Male Yes Fri Dinner 4 1.0 90 28.97 3.00 Male Yes Fri Dinner 2 2.0 170 50.81 10.00 Male Yes Sat Dinner 3 1.0 212 48.33 9.00 Male No Sat Dinner 4 2.0 156 48.17 5.00 Male No Sun Dinner 6 1.0 182 45.35 3.50 Male Yes Sun Dinner 3 2.0 197 43.11 5.00 Female Yes Thur Lunch 4 1.0 142 41.19 5.00 Male No Thur Lunch 5 2.0
-- Oracle's RANK() analytic function SELECT * FROM ( SELECT t.*, RANK() OVER(PARTITION BY sex ORDER BY tip) AS rnk FROM tips t WHERE tip < 2 ) WHERE rnk < 3 ORDER BY sex, rnk;
让我们找到每个性别组中 (rank < 3) 的小费,对于 (tips < 2)。请注意,当使用 rank(method='min')
函数时,相同 tip
的 rnk_min
保持不变(类似于 Oracle 的 RANK()
函数)
In [40]: ( ....: tips[tips["tip"] < 2] ....: .assign(rnk_min=tips.groupby(["sex"])["tip"].rank(method="min")) ....: .query("rnk_min < 3") ....: .sort_values(["sex", "rnk_min"]) ....: ) ....: Out[40]: total_bill tip sex smoker day time size rnk_min 67 3.07 1.00 Female Yes Sat Dinner 1 1.0 92 5.75 1.00 Female Yes Fri Dinner 2 1.0 111 7.25 1.00 Female No Sat Dinner 1 1.0 236 12.60 1.00 Male Yes Sat Dinner 2 1.0 237 32.83 1.17 Male Yes Sat Dinner 2 2.0
更新
UPDATE tips SET tip = tip*2 WHERE tip < 2;
In [41]: tips.loc[tips["tip"] < 2, "tip"] *= 2
删除
DELETE FROM tips WHERE tip > 9;
在 pandas 中,我们选择应该保留的行,而不是删除它们:
In [42]: tips = tips.loc[tips["tip"] <= 9]
与电子表格的比较
原文:
pandas.pydata.org/docs/getting_started/comparison/comparison_with_spreadsheets.html
由于许多潜在的 pandas 用户对电子表格程序(如 Excel)有一定的了解,因此本页面旨在提供使用 pandas 执行各种电子表格操作的示例。本页面将使用 Excel 的术语和链接到文档,但在 Google Sheets、LibreOffice Calc、Apple Numbers 和其他兼容 Excel 的电子表格软件中,情况将是相同/类似的。
如果您是 pandas 的新手,您可能首先想阅读 10 分钟入门 pandas 来熟悉该库。
惯例上,我们导入 pandas 和 NumPy 如下:
In [1]: import pandas as pd In [2]: import numpy as np
数据结构
通用术语翻译
pandas | Excel |
DataFrame |
工作表 |
Series |
列 |
Index |
行标题 |
行 | 行 |
NaN |
空单元格 |
DataFrame
在 pandas 中,DataFrame
类似于 Excel 工作表。虽然 Excel 工作簿可以包含多个工作表,但 pandas 的DataFrame
是独立存在的。
Series
Series
是表示DataFrame
的一列的数据结构。与处理电子表格的列类似,操作Series
。
Index
每个DataFrame
和Series
都有一个Index
,这些是数据的行上的标签。在 pandas 中,如果没有指定索引,默认使用 RangeIndex
(第一行 = 0,第二行 = 1,依此类推),类似于电子表格中的行标题/编号。
在 pandas 中,索引可以设置为一个(或多个)唯一值,就像在工作表中使用作为行标识符的列一样。与大多数电子表格不同,这些Index
值实际上可以用于引用行。(请注意,在 Excel 中可以使用结构引用执行此操作。)例如,在电子表格中,您可以将第一行引用为A1:Z1
,而在 pandas 中,您可以使用populations.loc['Chicago']
。
索引值也是持久的,因此���果重新排列DataFrame
中的行,特定行的标签不会改变。
查看 索引文档 以了解如何有效使用Index
。
复制 vs. 原地操作
大多数 pandas 操作返回Series
/DataFrame
的副本。要使更改“生效”,您需要将其分配给一个新变量:
sorted_df = df.sort_values("col1")
或覆盖原始数据:
df = df.sort_values("col1")
注意
您将看到一些方法可用的 inplace=True
或 copy=False
关键字参数:
df.replace(5, inplace=True)
目前正在就大多数方法(例如 dropna
)废弃和移除 inplace
和 copy
进行积极讨论,除了一小部分方法(包括 replace
)之外。在写时复制的情况下,这两个关键字将不再必要。提案可以在这里找到。
数据输入/输出
从值构建 DataFrame
在电子表格中,值可以直接输入到单元格中。
一个 pandas DataFrame
可以以许多不同的方式构建,但对于少量值,通常将其指定为 Python 字典是方便的,其中键是列名,值是数据。
In [3]: df = pd.DataFrame({"x": [1, 3, 5], "y": [2, 4, 6]}) In [4]: df Out[4]: x y 0 1 2 1 3 4 2 5 6
读取外部数据
Excel 和 pandas 都可以从各种来源以各种格式导入数据。
CSV
让我们加载并显示来自 pandas 测试的tips数据集,这是一个 CSV 文件。在 Excel 中,您会下载然后打开 CSV。在 pandas 中,您将 URL 或本地路径传递给 read_csv()
:
In [5]: url = ( ...: "https://raw.githubusercontent.com/pandas-dev" ...: "/pandas/main/pandas/tests/io/data/csv/tips.csv" ...: ) ...: In [6]: tips = pd.read_csv(url) In [7]: tips Out[7]: total_bill tip sex smoker day time size 0 16.99 1.01 Female No Sun Dinner 2 1 10.34 1.66 Male No Sun Dinner 3 2 21.01 3.50 Male No Sun Dinner 3 3 23.68 3.31 Male No Sun Dinner 2 4 24.59 3.61 Female No Sun Dinner 4 .. ... ... ... ... ... ... ... 239 29.03 5.92 Male No Sat Dinner 3 240 27.18 2.00 Female Yes Sat Dinner 2 241 22.67 2.00 Male Yes Sat Dinner 2 242 17.82 1.75 Male No Sat Dinner 2 243 18.78 3.00 Female No Thur Dinner 2 [244 rows x 7 columns]
像Excel 的文本导入向导一样,read_csv
可以接受多个参数来指定数据应如何解析。例如,如果数据实际上是制表符分隔的,并且没有列名,那么 pandas 命令将是:
tips = pd.read_csv("tips.csv", sep="\t", header=None) # alternatively, read_table is an alias to read_csv with tab delimiter tips = pd.read_table("tips.csv", header=None)
Excel 文件
Excel 通过双击打开各种 Excel 文件格式,或使用打开菜单。在 pandas 中,您可以使用特殊方法来读取和写入 Excel 文件。
让我们首先根据上面示例中的 tips
数据框创建一个新的 Excel 文件:
tips.to_excel("./tips.xlsx")
如果您希望随后访问 tips.xlsx
文件中的数据,可以使用以下方式将其读入您的模块中
tips_df = pd.read_excel("./tips.xlsx", index_col=0)
你刚刚使用 pandas 读取了一个 Excel 文件!
限制输出
电子表格程序一次只会显示一个屏幕的数据,然后允许你滚动,因此实际上不需要限制输出。在 pandas 中,你需要更多地考虑如何控制你的DataFrame
的显示方式。
默认情况下,pandas 会截断大型DataFrame
的输出以显示第一行和最后一行。这可以通过更改 pandas 选项,或使用DataFrame.head()
或DataFrame.tail()
来覆盖。
In [8]: tips.head(5) Out[8]: total_bill tip sex smoker day time size 0 16.99 1.01 Female No Sun Dinner 2 1 10.34 1.66 Male No Sun Dinner 3 2 21.01 3.50 Male No Sun Dinner 3 3 23.68 3.31 Male No Sun Dinner 2 4 24.59 3.61 Female No Sun Dinner 4
导出数据
默认情况下,桌面电子表格软件会保存到其相应的文件格式(.xlsx
,.ods
等)。但是,你可以保存到其他文件格式。
pandas 可以创建 Excel 文件,CSV,或其他多种格式。
数据操作
列上的操作
在电子表格中,公式通常在单独的单元格中创建,然后通过拖动到其他单元格中以计算其他列的值。在 pandas 中,你可以直接对整列进行操作。
pandas 通过在DataFrame
中指定单独的Series
提供矢量化操作。新列可以以相同的方式分配。DataFrame.drop()
方法从DataFrame
中删除列。
In [9]: tips["total_bill"] = tips["total_bill"] - 2 In [10]: tips["new_bill"] = tips["total_bill"] / 2 In [11]: tips Out[11]: total_bill tip sex smoker day time size new_bill 0 14.99 1.01 Female No Sun Dinner 2 7.495 1 8.34 1.66 Male No Sun Dinner 3 4.170 2 19.01 3.50 Male No Sun Dinner 3 9.505 3 21.68 3.31 Male No Sun Dinner 2 10.840 4 22.59 3.61 Female No Sun Dinner 4 11.295 .. ... ... ... ... ... ... ... ... 239 27.03 5.92 Male No Sat Dinner 3 13.515 240 25.18 2.00 Female Yes Sat Dinner 2 12.590 241 20.67 2.00 Male Yes Sat Dinner 2 10.335 242 15.82 1.75 Male No Sat Dinner 2 7.910 243 16.78 3.00 Female No Thur Dinner 2 8.390 [244 rows x 8 columns] In [12]: tips = tips.drop("new_bill", axis=1)
请注意,我们不需要逐个单元格地告诉它执行减法 — pandas 会为我们处理。查看如何从现有列创建新列。
过滤
数据框可以通过多种方式进行过滤;其中最直观的是使用布尔索引。
In [13]: tips[tips["total_bill"] > 10] Out[13]: total_bill tip sex smoker day time size 0 14.99 1.01 Female No Sun Dinner 2 2 19.01 3.50 Male No Sun Dinner 3 3 21.68 3.31 Male No Sun Dinner 2 4 22.59 3.61 Female No Sun Dinner 4 5 23.29 4.71 Male No Sun Dinner 4 .. ... ... ... ... ... ... ... 239 27.03 5.92 Male No Sat Dinner 3 240 25.18 2.00 Female Yes Sat Dinner 2 241 20.67 2.00 Male Yes Sat Dinner 2 242 15.82 1.75 Male No Sat Dinner 2 243 16.78 3.00 Female No Thur Dinner 2 [204 rows x 7 columns]
上述语句只是将True
/False
对象的Series
传递给数据框,返回所有具有True
的��。
In [14]: is_dinner = tips["time"] == "Dinner" In [15]: is_dinner Out[15]: 0 True 1 True 2 True 3 True 4 True ... 239 True 240 True 241 True 242 True 243 True Name: time, Length: 244, dtype: bool In [16]: is_dinner.value_counts() Out[16]: time True 176 False 68 Name: count, dtype: int64 In [17]: tips[is_dinner] Out[17]: total_bill tip sex smoker day time size 0 14.99 1.01 Female No Sun Dinner 2 1 8.34 1.66 Male No Sun Dinner 3 2 19.01 3.50 Male No Sun Dinner 3 3 21.68 3.31 Male No Sun Dinner 2 4 22.59 3.61 Female No Sun Dinner 4 .. ... ... ... ... ... ... ... 239 27.03 5.92 Male No Sat Dinner 3 240 25.18 2.00 Female Yes Sat Dinner 2 241 20.67 2.00 Male Yes Sat Dinner 2 242 15.82 1.75 Male No Sat Dinner 2 243 16.78 3.00 Female No Thur Dinner 2 [176 rows x 7 columns]
If/then 逻辑
假设我们想要根据total_bill
是小于还是大于$10 来创建一个bucket
列,值为low
和high
。
在电子表格中,可以使用条件公式进行逻辑比较。我们会使用公式=IF(A2 < 10, "low", "high")
,拖动到新的bucket
列中的所有单元格。
在 pandas 中,可以使用numpy
中的where
方法来完成相同的操作。
In [18]: tips["bucket"] = np.where(tips["total_bill"] < 10, "low", "high") In [19]: tips Out[19]: total_bill tip sex smoker day time size bucket 0 14.99 1.01 Female No Sun Dinner 2 high 1 8.34 1.66 Male No Sun Dinner 3 low 2 19.01 3.50 Male No Sun Dinner 3 high 3 21.68 3.31 Male No Sun Dinner 2 high 4 22.59 3.61 Female No Sun Dinner 4 high .. ... ... ... ... ... ... ... ... 239 27.03 5.92 Male No Sat Dinner 3 high 240 25.18 2.00 Female Yes Sat Dinner 2 high 241 20.67 2.00 Male Yes Sat Dinner 2 high 242 15.82 1.75 Male No Sat Dinner 2 high 243 16.78 3.00 Female No Thur Dinner 2 high [244 rows x 8 columns]
日期功能
本节将涉及“日期”,但时间戳处理方式类似。
我们可以将日期功能分为两部分:解析和输出。在电子表格中,日期值通常会自动解析,尽管如果需要,可以使用DATEVALUE函数。在 pandas 中,您需要显式将纯文本转换为日期时间对象,可以在从 CSV 读取时或在 DataFrame 中的某个时刻进行转换。
解析后,电子表格会以默认格式显示日期,尽管格式可以更改。在 pandas 中,您通常希望在进行计算时将日期保留为datetime
对象。在电子表格中,输出日期的部分(如年份)是通过日期函数完成的,在 pandas 中则通过 datetime 属性完成。
在电子表格中,如果在列A
和B
中给出date1
和date2
,你可能会有这些公式:
列 | 公式 |
date1_year |
=YEAR(A2) |
date2_month |
=MONTH(B2) |
date1_next |
=DATE(YEAR(A2),MONTH(A2)+1,1) |
months_between |
=DATEDIF(A2,B2,"M") |
下面显示了等效的 pandas 操作。
In [20]: tips["date1"] = pd.Timestamp("2013-01-15") In [21]: tips["date2"] = pd.Timestamp("2015-02-15") In [22]: tips["date1_year"] = tips["date1"].dt.year In [23]: tips["date2_month"] = tips["date2"].dt.month In [24]: tips["date1_next"] = tips["date1"] + pd.offsets.MonthBegin() In [25]: tips["months_between"] = tips["date2"].dt.to_period("M") - tips[ ....: "date1" ....: ].dt.to_period("M") ....: In [26]: tips[ ....: ["date1", "date2", "date1_year", "date2_month", "date1_next", "months_between"] ....: ] ....: Out[26]: date1 date2 date1_year date2_month date1_next months_between 0 2013-01-15 2015-02-15 2013 2 2013-02-01 <25 * MonthEnds> 1 2013-01-15 2015-02-15 2013 2 2013-02-01 <25 * MonthEnds> 2 2013-01-15 2015-02-15 2013 2 2013-02-01 <25 * MonthEnds> 3 2013-01-15 2015-02-15 2013 2 2013-02-01 <25 * MonthEnds> 4 2013-01-15 2015-02-15 2013 2 2013-02-01 <25 * MonthEnds> .. ... ... ... ... ... ... 239 2013-01-15 2015-02-15 2013 2 2013-02-01 <25 * MonthEnds> 240 2013-01-15 2015-02-15 2013 2 2013-02-01 <25 * MonthEnds> 241 2013-01-15 2015-02-15 2013 2 2013-02-01 <25 * MonthEnds> 242 2013-01-15 2015-02-15 2013 2 2013-02-01 <25 * MonthEnds> 243 2013-01-15 2015-02-15 2013 2 2013-02-01 <25 * MonthEnds> [244 rows x 6 columns]
查看时间序列/日期功能以获取更多详细信息。
列的选择
在电子表格中,您可以通过以下方式选择要选择的列:
由于电子表格列通常在标题行中命名,所以重命名列只是简单地更改该第一个单元格中的文本。
pandas 中使用相同的操作如下所示。
保留某些列
In [27]: tips[["sex", "total_bill", "tip"]] Out[27]: sex total_bill tip 0 Female 14.99 1.01 1 Male 8.34 1.66 2 Male 19.01 3.50 3 Male 21.68 3.31 4 Female 22.59 3.61 .. ... ... ... 239 Male 27.03 5.92 240 Female 25.18 2.00 241 Male 20.67 2.00 242 Male 15.82 1.75 243 Female 16.78 3.00 [244 rows x 3 columns]
删除列
In [28]: tips.drop("sex", axis=1) Out[28]: total_bill tip smoker day time size 0 14.99 1.01 No Sun Dinner 2 1 8.34 1.66 No Sun Dinner 3 2 19.01 3.50 No Sun Dinner 3 3 21.68 3.31 No Sun Dinner 2 4 22.59 3.61 No Sun Dinner 4 .. ... ... ... ... ... ... 239 27.03 5.92 No Sat Dinner 3 240 25.18 2.00 Yes Sat Dinner 2 241 20.67 2.00 Yes Sat Dinner 2 242 15.82 1.75 No Sat Dinner 2 243 16.78 3.00 No Thur Dinner 2 [244 rows x 6 columns]
重命名列
In [29]: tips.rename(columns={"total_bill": "total_bill_2"}) Out[29]: total_bill_2 tip sex smoker day time size 0 14.99 1.01 Female No Sun Dinner 2 1 8.34 1.66 Male No Sun Dinner 3 2 19.01 3.50 Male No Sun Dinner 3 3 21.68 3.31 Male No Sun Dinner 2 4 22.59 3.61 Female No Sun Dinner 4 .. ... ... ... ... ... ... ... 239 27.03 5.92 Male No Sat Dinner 3 240 25.18 2.00 Female Yes Sat Dinner 2 241 20.67 2.00 Male Yes Sat Dinner 2 242 15.82 1.75 Male No Sat Dinner 2 243 16.78 3.00 Female No Thur Dinner 2 [244 rows x 7 columns]
按值排序
在电子表格中进行排序是通过排序对话框完成的。
pandas 有一个DataFrame.sort_values()
方法,它接受要按列排序的列列表。
In [30]: tips = tips.sort_values(["sex", "total_bill"]) In [31]: tips Out[31]: total_bill tip sex smoker day time size 67 1.07 1.00 Female Yes Sat Dinner 1 92 3.75 1.00 Female Yes Fri Dinner 2 111 5.25 1.00 Female No Sat Dinner 1 145 6.35 1.50 Female No Thur Lunch 2 135 6.51 1.25 Female No Thur Lunch 2 .. ... ... ... ... ... ... ... 182 43.35 3.50 Male Yes Sun Dinner 3 156 46.17 5.00 Male No Sun Dinner 6 59 46.27 6.73 Male No Sat Dinner 4 212 46.33 9.00 Male No Sat Dinner 4 170 48.81 10.00 Male Yes Sat Dinner 3 [244 rows x 7 columns]
字符串处理
查找字符串的长度
在电子表格中,可以使用LEN函数找到文本中的字符数。这可以与TRIM函数一起使用以删除额外的空格。
=LEN(TRIM(A2)) • 1
您可以使用Series.str.len()
找到字符字符串的长度。在 Python 3 中,所有字符串都是 Unicode 字符串。len
包括尾随空格。使用len
和rstrip
排除尾随空格。
In [32]: tips["time"].str.len() Out[32]: 67 6 92 6 111 6 145 5 135 5 .. 182 6 156 6 59 6 212 6 170 6 Name: time, Length: 244, dtype: int64 In [33]: tips["time"].str.rstrip().str.len() Out[33]: 67 6 92 6 111 6 145 5 135 5 .. 182 6 156 6 59 6 212 6 170 6 Name: time, Length: 244, dtype: int64
请注意,这仍将包括字符串中的多个空格,因此不是 100%等效。
查找子串的位置
FIND电子表格函数返回子字符串的位置,第一个字符为1
。
您可以使用Series.str.find()
方法在字符串列中查找字符的位置。find
搜索子字符串的第一个位置。如果找到子字符串,则该方法返回其位置。如果未找到,则返回-1
。请记住,Python 索引是从零开始的。
In [34]: tips["sex"].str.find("ale") Out[34]: 67 3 92 3 111 3 145 3 135 3 .. 182 1 156 1 59 1 212 1 170 1 Name: sex, Length: 244, dtype: int64
根据位置提取子串
电子表格中有一个MID公式,用于从给定位置提取子串。要获取第一个字符:
=MID(A2,1,1) • 1
使用 pandas,您可以使用[]
符号根据位置提取字符串中的子串。请记住,Python 索引是从零开始的。
In [35]: tips["sex"].str[0:1] Out[35]: 67 F 92 F 111 F 145 F 135 F .. 182 M 156 M 59 M 212 M 170 M Name: sex, Length: 244, dtype: object
提取第 n 个单词
在 Excel 中,您可能会使用文本分列向导来拆分文本并检索特定列。(注意也可以通过公式来实现。)
在 pandas 中提取单词的最简单方法是通过空格拆分字符串,然后按索引引用单词。注意,如果需要的话,还有更强大的方法。
In [36]: firstlast = pd.DataFrame({"String": ["John Smith", "Jane Cook"]}) In [37]: firstlast["First_Name"] = firstlast["String"].str.split(" ", expand=True)[0] In [38]: firstlast["Last_Name"] = firstlast["String"].str.rsplit(" ", expand=True)[1] In [39]: firstlast Out[39]: String First_Name Last_Name 0 John Smith John Smith 1 Jane Cook Jane Cook
更改大小写
电子表格提供UPPER、LOWER 和 PROPER 函数,分别用于将文本转换为大写、小写和首字母大写。
等效的 pandas 方法分别是Series.str.upper()
、Series.str.lower()
和Series.str.title()
。
In [40]: firstlast = pd.DataFrame({"string": ["John Smith", "Jane Cook"]}) In [41]: firstlast["upper"] = firstlast["string"].str.upper() In [42]: firstlast["lower"] = firstlast["string"].str.lower() In [43]: firstlast["title"] = firstlast["string"].str.title() In [44]: firstlast Out[44]: string upper lower title 0 John Smith JOHN SMITH john smith John Smith 1 Jane Cook JANE COOK jane cook Jane Cook
合并
下面的表将用于合并示例:
In [45]: df1 = pd.DataFrame({"key": ["A", "B", "C", "D"], "value": np.random.randn(4)}) In [46]: df1 Out[46]: key value 0 A 0.469112 1 B -0.282863 2 C -1.509059 3 D -1.135632 In [47]: df2 = pd.DataFrame({"key": ["B", "D", "D", "E"], "value": np.random.randn(4)}) In [48]: df2 Out[48]: key value 0 B 1.212112 1 D -0.173215 2 D 0.119209 3 E -1.044236
在 Excel 中,可以通过 VLOOKUP 合并表格。
pandas 数据帧有一个merge()
方法,提供类似的功能。数据不需要提前排序,并且不同的连接类型通过how
关键字实现。
In [49]: inner_join = df1.merge(df2, on=["key"], how="inner") In [50]: inner_join Out[50]: key value_x value_y 0 B -0.282863 1.212112 1 D -1.135632 -0.173215 2 D -1.135632 0.119209 In [51]: left_join = df1.merge(df2, on=["key"], how="left") In [52]: left_join Out[52]: key value_x value_y 0 A 0.469112 NaN 1 B -0.282863 1.212112 2 C -1.509059 NaN 3 D -1.135632 -0.173215 4 D -1.135632 0.119209 In [53]: right_join = df1.merge(df2, on=["key"], how="right") In [54]: right_join Out[54]: key value_x value_y 0 B -0.282863 1.212112 1 D -1.135632 -0.173215 2 D -1.135632 0.119209 3 E NaN -1.044236 In [55]: outer_join = df1.merge(df2, on=["key"], how="outer") In [56]: outer_join Out[56]: key value_x value_y 0 A 0.469112 NaN 1 B -0.282863 1.212112 2 C -1.509059 NaN 3 D -1.135632 -0.173215 4 D -1.135632 0.119209 5 E NaN -1.044236
merge
相对于VLOOKUP
有一些优势:
- 查找值不需要是查找表的第一列
- 如果匹配了多行,则每个匹配都会有一行,而不仅仅是第一个
- 它将包括查找表中的所有列,而不仅仅是单个指定的列
- 它支持更复杂的连接操作
Pandas 2.2 中文官方教程和指南(四)(3)https://developer.aliyun.com/article/1509882