只会Pandas?来学习这25种Pandas变SQL的方法,让你的数据分析更得心应手!

只会Pandas?来学习这25种Pandas变SQL的方法,让你的数据分析更得心应手!

为什么要学习这些?

毫无疑问,SQL和Pandas都是数据科学家处理数据的强大工具。一般来说,SQL是一种用于管理和操作数据库中数据的语言,而Pandas是Python中的数据操作和分析库。如果你想了解更多关于SQL的相关内容,可以阅读以下这些文章:
使用SQL总结A/B实验结果
数据科学面试中你应该知道的10个高级SQL概念
SQL & NoSQL,掌握这7点就够了
SQL数据清理及准备 – 看这一篇就够了

此外,SQL通常用于从数据库中提取数据,在Python中进行分析(主要使用Pandas)。它的工具和功能齐全,能很好地处理表格数据,如数据操作、数据分析和可视化等。

将SQL和Pandas一起使用,我们就能清理、变换和分析大型数据集,创建复杂的数据管道和模型,这对作为数据科学家大有裨益,也因此,我们必须精通它们。在本文中,我将带你一步一步走,一起将最常见的Pandas操作变为SQL查询。

我们开始吧!

数据集

出于演示目的,我使用Faker创建了一个虚拟数据集:

随机员工数据集(图片由作者提供)

#1读取CSV文件

Pandas

CSV是最常用的用于读取Pandas数据帧的文件格式,我们需要用好Pandas中的pd.read_csv()。

file = "data.csv"
df = pd.read_csv(file)

SQL

要想在数据库中创建表,我们首先要创建一个空表,定义其框架。

%%sql
drop table if exists employee;
CREATE TABLE employee
(
    ID                integer,
    first_name        varchar(20),
    last_name         varchar(20),
    gender            varchar(2),
    salary            integer,
    level             integer,
    date_of_joining   date
);

然后,我们将CSV文件的内容(如果第一行是标题,则从第二行开始)转储到上面创建的表中。

%%sql

LOAD DATA INFILE 'data.csv'
INTO TABLE employee
FIELDS TERMINATED BY ','
LINES TERMINATED BY '\n'
IGNORE 1 ROWS;

输出

完成此数据帧/表后,我们将获得以下输出:

读取CSV后的输出(图片由作者提供)

#2显示前X行

Pandas

我们可以在Pandas中使用df.head()。

df.head()
 ID first_name last_name gender  salary  level date_of_joining
0   1      Peter   Sanders      M   10000      2      2020-10-03
1   2      Julie    Miller      F   12000      2      2020-01-14
2   3     Rachel      Bray      F    9000      1      2020-09-03
3   4      Priti   Agarwal      F   10000      2      2020-01-03
4   5      David       Cox      M    5000      1      2020-05-28

SQL

在MySQL语法中,我们可以在select之后使用limit,并指定要显示的记录数。

%%sql
select * from employee limit 5;
 * sqlite://
Done.
ID   first_name   last_name   gender   salary   level   date_of_joining
1   Peter   Sanders   M   10000   2   2020-03-10
2   Julie   Miller   F   12000   2   2020-01-14
3   Rachel   Bray   F   9000   1   2020-03-09
4   Priti   Agarwal   F   10000   2   2020-03-01
5   David   Cox   M   5000   1   2020-05-28

#3输出尺寸

Pandas

根据表的shape属性输出行数和列数。

df.shape
(10, 7)

SQL

我们可以使用“count”来输出行数。

%%sql
select count(1) from employee;
 * sqlite://
Done.
count(1)
10

#4输出数据类型

Pandas

在这里,我们可以使用dtypes参数输出所有列的数据类型:

df.dtypes
ID                  int64
first_name         object
last_name          object
gender             object
salary              int64
level               int64
date_of_joining    object
dtype: object

SQL

接着,我们可以按如下方式输出数据类型:

%%sql
DESCRIBE employee;

#5修改列的数据类型

Pandas

在这里,我们可以使用如下的astype():

df.ID.astype(str)
0     1
1     2
2     3
3     4
4     5
5     6
6     7
7     8
8     9
9    10
Name: ID, dtype: object

SQL

使用ALTER COLUMN更改列的数据类型。

%%sql
ALTER TABLE employee
ALTER COLUMN ID varchar(5);

以上操作将永久修改表中列的数据类型。如果你只希望在过滤时执行此操作,请使用cast。

%%sql
select cast(ID as string)
from employee
 * sqlite://
Done.
cast(ID as string)
1
2
3
4
5
6
7
8
9
10

#6–11过滤数据

在Pandas中有多种过滤数据帧的方法。

#6:你可以按如下方式过滤一列:

print(df[df.gender == "M"])
   ID first_name last_name gender  salary  level date_of_joining
0   1      Peter   Sanders      M   10000      2      2020-10-03
4   5      David       Cox      M    5000      1      2020-05-28
6   7       John     Frank      M   13000      3      2019-12-11
7   8       Mark  Franklin      M   13500      3      2019-12-11
9  10      Brock    Murray      M   11000      2      2020-02-13

可以将上述内容变换为SQL,如下所示:

%%sql

select * 
from employee 
where gender = "M";
 * sqlite://
Done.
ID   first_name   last_name   gender   salary   level   date_of_joining
1   Peter   Sanders   M   10000   2   2020-03-10
5   David   Cox   M   5000   1   2020-05-28
7   John   Frank   M   13000   3   2019-11-12
8   Mark   Franklin   M   13500   3   2019-11-12
10   Brock   Murray   M   11000   2   2020-02-13

#7:此外,你还可以在多个列上进行过滤:

print(df[(df.gender == "M") & (df.level == 2)])
   ID first_name last_name gender  salary  level date_of_joining
0   1      Peter   Sanders      M   10000      2      2020-10-03
9  10      Brock    Murray      M   11000      2      2020-02-13

同样地,我们变换为SQL:

%%sql

select * 
from employee 
where gender = "M" and level = 2;
 * sqlite://
Done.
ID   first_name   last_name   gender   salary   level   date_of_joining
1   Peter   Sanders   M   10000   2   2020-03-10
10   Brock   Murray   M   11000   2   2020-02-13

#8:你还可以使用isin()从值列表中筛选:

print(df[df.level.isin([3,4])])
   ID first_name last_name gender  salary  level date_of_joining
6   7       John     Frank      M   13000      3      2019-12-11
7   8       Mark  Franklin      M   13500      3      2019-12-11
8   9   Cristina       Rel      F   15000      4      2019-09-22

为了模拟上述情况,我们在SQL中使用了“in”:

%%sql

select * 
from employee 
where level in (3,4);
 * sqlite://
Done.
ID   first_name   last_name   gender   salary   level   date_of_joining
7   John   Frank   M   13000   3   2019-11-12
8   Mark   Franklin   M   13500   3   2019-11-12
9   Cristina   Rel   F   15000   4   2019-09-22

#9:在Pandas中,你还可以使用点运算符选择特定的列。

df.first_name.head(3)
0     Peter
1     Julie
2    Rachel
Name: first_name, dtype: object

在SQL中,我们可以在select之后指定所需的列。

%%sql

select first_name
from employee 
limit 3;
* sqlite://
Done.
first_name
Peter
Julie
Rachel

#10:如果要在Pandas中选择多个列,可以执行以下操作:

df[["first_name", "date_of_joining"]].head(3)
  first_name date_of_joining
0      Peter      2020-10-03
1      Julie      2020-01-14
2     Rachel      2020-09-03

在SQL中的select之后选择多个列,也同样如此:

%%sql

select first_name, date_of_joining
from employee 
limit 3;
 * sqlite://
Done.
first_name   date_of_joining
Peter   2020-03-10
Julie   2020-01-14
Rachel   2020-03-09

#11你还可以根据Pandas中的NaN值进行过滤

df[df.first_name.isna()]
Empty DataFrame
Columns: [ID, first_name, last_name, gender, salary, level, date_of_joining]
Index: []

我们没有NaN值,因此看不到行。

如果是SQL,如下所示:

%%sql

select *
from employee 
where first_name is NULL;
* sqlite://
Done.
ID   first_name   last_name   gender   salary   level   date_of_joining

#12我们还可以尝试一些复杂的字符串过滤

df[df.first_name.str.startswith("J")]
   ID first_name last_name gender  salary  level date_of_joining
1   2      Julie    Miller      F   12000      2      2020-01-14
6   7       John     Frank      M   13000      3      2019-12-11

在SQL中,我们可以使用LIKE语句。

%%sql

select * 
from employee 
where first_name LIKE "J%";
 * sqlite://
Done.
ID   first_name   last_name   gender   Employee_Salary   level   date_of_joining   full_name
2   Julie   Miller   F   12000   2   2020-01-14   Julie Miller
7   John   Frank   M   13000   3   2019-11-12   John Frank

#13你还可以搜索其中的子字符串。假设现在我们要查找“last_name”包含子字符串“an”的所有记录

在Pandas中,我们可以执行以下操作:

print(df[df.last_name.str.contains("an")])
   ID first_name last_name gender  salary  level date_of_joining
0   1      Peter   Sanders      M   10000      2      2020-10-03
6   7       John     Frank      M   13000      3      2019-12-11
7   8       Mark  Franklin      M   13500      3      2019-12-11

在SQL中,我们可以再次使用LIKE语句。

%%sql

select * 
from employee 
where last_name LIKE "%an%";
 * sqlite://
Done.
last_name   gender   Employee_Salary   level   date_of_joining   full_name
1   Peter   Sanders   M   10000   2   2020-03-10   Peter Sanders
7   John   Frank   M   13000   3   2019-11-12   John Frank
8   Mark   Franklin   M   13500   3   2019-11-12   Mark Franklin

#14–16排序数据

排序是数据科学家用来对数据分等级的另一个操作。

Pandas

使用df.sort_values()对数据帧进行排序。

df.sort_values("salary")
   ID first_name last_name gender  salary  level date_of_joining
4   5      David       Cox      M    5000      1      2020-05-28
5   6      Helly     Raval      F    8000      1      2020-06-19
2   3     Rachel      Bray      F    9000      1      2020-09-03
0   1      Peter   Sanders      M   10000      2      2020-10-03
3   4      Priti   Agarwal      F   10000      2      2020-01-03
9  10      Brock    Murray      M   11000      2      2020-02-13
1   2      Julie    Miller      F   12000      2      2020-01-14
6   7       John     Frank      M   13000      3      2019-12-11
7   8       Mark  Franklin      M   13500      3      2019-12-11
8   9   Cristina       Rel      F   15000      4      2019-09-22

你还可以对多个列进行排序:

print(df.sort_values(["salary", "level"]))
   ID first_name last_name gender  salary  level date_of_joining
4   5      David       Cox      M    5000      1      2020-05-28
5   6      Helly     Raval      F    8000      1      2020-06-19
2   3     Rachel      Bray      F    9000      1      2020-09-03
0   1      Peter   Sanders      M   10000      2      2020-10-03
3   4      Priti   Agarwal      F   10000      2      2020-01-03
9  10      Brock    Murray      M   11000      2      2020-02-13
1   2      Julie    Miller      F   12000      2      2020-01-14
6   7       John     Frank      M   13000      3      2019-12-11
7   8       Mark  Franklin      M   13500      3      2019-12-11
8   9   Cristina       Rel      F   15000      4      2019-09-22

最后,我们还可以使用ascending(升序)参数为不同的列指定不同的条件(升序/降序)

df.sort_values(["last_name", "level"], ascending=[False, True])
   ID first_name last_name gender  salary  level date_of_joining
0   1      Peter   Sanders      M   10000      2      2020-10-03
8   9   Cristina       Rel      F   15000      4      2019-09-22
5   6      Helly     Raval      F    8000      1      2020-06-19
9  10      Brock    Murray      M   11000      2      2020-02-13
1   2      Julie    Miller      F   12000      2      2020-01-14
7   8       Mark  Franklin      M   13500      3      2019-12-11
6   7       John     Frank      M   13000      3      2019-12-11
4   5      David       Cox      M    5000      1      2020-05-28
2   3     Rachel      Bray      F    9000      1      2020-09-03
3   4      Priti   Agarwal      F   10000      2      2020-01-03

这里,对应ascending的列表指示last_name按降序排序,而level按升序排序。

SQL

在SQL中,我们可以使用order by字句来执行此操作。

%%sql

select *
from employee 
order by salary;
* sqlite://
Done.
ID   first_name   last_name   gender   salary   level   date_of_joining
5   David   Cox   M   5000   1   2020-05-28
6   Helly   Raval   F   8000   1   2020-06-19
3   Rachel   Bray   F   9000   1   2020-03-09
1   Peter   Sanders   M   10000   2   2020-03-10
4   Priti   Agarwal   F   10000   2   2020-03-01
10   Brock   Murray   M   11000   2   2020-02-13
2   Julie   Miller   F   12000   2   2020-01-14
7   John   Frank   M   13000   3   2019-11-12
8   Mark   Franklin   M   13500   3   2019-11-12
9   Cristina   Rel   F   15000   4   2019-09-22

此外,通过在order by字句中指定更多列,我们可以容纳更多有排序条件的列:

%%sql

select *
from employee 
order by salary, level;

 * sqlite://
Done.
ID   first_name   last_name   gender   salary   level   date_of_joining
5   David   Cox   M   5000   1   2020-05-28
6   Helly   Raval   F   8000   1   2020-06-19
3   Rachel   Bray   F   9000   1   2020-03-09
1   Peter   Sanders   M   10000   2   2020-03-10
4   Priti   Agarwal   F   10000   2   2020-03-01
10   Brock   Murray   M   11000   2   2020-02-13
2   Julie   Miller   F   12000   2   2020-01-14
7   John   Frank   M   13000   3   2019-11-12
8   Mark   Franklin   M   13500   3   2019-11-12
9   Cristina   Rel   F   15000   4   2019-09-22

我们可以为不同的列指定不同的排序顺序,如下所示:

%%sql

select *
from employee 
order by last_name desc, level asc;
 * sqlite://
Done.
ID   first_name   last_name   gender   salary   level   date_of_joining
1   Peter   Sanders   M   10000   2   2020-03-10
9   Cristina   Rel   F   15000   4   2019-09-22
6   Helly   Raval   F   8000   1   2020-06-19
10   Brock   Murray   M   11000   2   2020-02-13
2   Julie   Miller   F   12000   2   2020-01-14
8   Mark   Franklin   M   13500   3   2019-11-12
7   John   Frank   M   13000   3   2019-11-12
5   David   Cox   M   5000   1   2020-05-28
3   Rachel   Bray   F   9000   1   2020-03-09
4   Priti   Agarwal   F   10000   2   2020-03-01

#17填充NaN值

在此,我删除了“薪水”列中的几个值。这是更新后的数据帧:

print(df.head())
   ID first_name last_name gender   salary  level date_of_joining
0   1      Peter   Sanders      M      NaN      2      2020-10-03
1   2      Julie    Miller      F      NaN      2      2020-01-14
2   3     Rachel      Bray      F   9000.0      1      2020-09-03
3   4      Priti   Agarwal      F  10000.0      2      2020-01-03
4   5      David       Cox      M   5000.0      1      2020-05-28

Pandas

在Pandas中,我们可以使用fillna()来填充NaN值:

df.salary.fillna(10000).head()
0    10000.0
1    10000.0
2     9000.0
3    10000.0
4     5000.0
Name: salary, dtype: float64

SQL

在SQL中,我们可以使用选择语句。

%%sql

select 
case when 
     salary is NULL then 10000 else salary end as salary 
from employee
limit 5;
 * sqlite://
Done.
salary
10000
10000
9000
10000
5000

#18–19连接数据

Pandas

如果要合并两个数据帧,可以使用pd.merge():

df1 = ...

df2 = ...

print(df1)
print(df2)
   col1  col2 col3
0     1     2    A
1     3     4    B
2     5     6    C
  col3 col4
0    A    X
1    B    Y
pd.merge(df1, df2, on = "col3")
   col1  col2 col3 col4
0     1     2    A    X
1     3     4    B    Y

SQL

%%sql

select * from
table1 join table2 
on (table1.col3 = table2.col3);
 * sqlite://
Done.
col1   col2   col3   col3_1   col4
1   2   A   A   X
3   4   B   B   Y

另一种方法是连接它们。

Pandas

看下面的数据帧:

df1 = ...
print(df1)
   col1  col2 col3
0     1     2    A
1     3     4    B
2     5     6    C

在Pandas中,你可以使用concat(),将其传给另一个数据帧,将其连接为列表/元组。

pd.concat((df1, df1))
   col1  col2 col3
0     1     2    A
1     3     4    B
2     5     6    C
0     1     2    A
1     3     4    B
2     5     6    C

SQL

使用SQL中的UNION(只保留特定行)和UNION ALL(保留所有行)也同样能做到。

%%sql

select * from table1
union all
select * from table1;
 * sqlite://
Done.
col1   col2   col3
1   2   A
3   4   B
5   6   C
1   2   A
3   4   B
5   6   C

#20分组数据

Pandas

要对数据帧进行分组并聚合,可以使用Pandas中的groupby(),如下所示:

df.groupby("level").salary.mean()
level
1     7333.333333
2    10750.000000
3    13250.000000
4    15000.000000
Name: salary, dtype: float64

SQL

在SQL中,可以使用GROUP BY字句在SELECT字句中指定聚合。

%%sql

select level, avg(salary)
from employee 
group by level;
 * sqlite://
Done.
level   avg(salary)
1   7333.333333333333
2   10750.0
3   13250.0
4   15000.0

结果都一样!

#21–22输出特定值

Pandas

要输出列中不同的值,使用unique()

df.level.unique()
array([2, 1, 3, 4])

要输出不同值的数量,使用nunique()。

df.level.nunique()
4

SQL

在SQL中,我们可以在select中使用DISTINCT,如下所示:

%%sql

select distinct level
from employee;
 * sqlite://
Done.
level
2
1
3
4

要计算SQL中不同值的数量,我们可以将COUNT aggregator装给distinct。

%%sql

select count(distinct level)
from employee;
 * sqlite://
Done.
count(distinct level)
4

#23重命名列

Pandas

我们可以使用df.rename(),如下所示:

df.rename(columns = {"salary":"Employee_Salary"}).head()
   ID first_name last_name gender  Employee_Salary  level date_of_joining
0   1      Peter   Sanders      M            10000      2      2020-10-03
1   2      Julie    Miller      F            12000      2      2020-01-14
2   3     Rachel      Bray      F             9000      1      2020-09-03
3   4      Priti   Agarwal      F            10000      2      2020-01-03
4   5      David       Cox      M             5000      1      2020-05-28

SQL

我们可以使用ALTER TABLE来重命名列:

%%sql

ALTER TABLE employee 
RENAME COLUMN salary to Employee_Salary;
 * sqlite://
Done.
1

#24删除列

Pandas

使用df.drop():

df.drop(columns = ["last_name"]).head()
   ID first_name gender  salary  level date_of_joining
0   1      Peter      M   10000      2      2020-10-03
1   2      Julie      F   12000      2      2020-01-14
2   3     Rachel      F    9000      1      2020-09-03
3   4      Priti      F   10000      2      2020-01-03
4   5      David      M    5000      1      2020-05-28

SQL

与重命名类似,我们可以使用ALTER TABLE和RENAME来删除。

%%sql

ALTER TABLE employee 
DROP COLUMN last_name;

#25创建新列

假设我们要创建一个新的列“full_name”,它是列first_name和last_name的连接,中间有一个空格。

Pandas

我们可以在Pandas中进行一个简单的赋值运算。

df["full_name"] = df["first_name"] + " " + df["last_name"]
   ID first_name last_name gender  salary  level date_of_joining      full_name
0   1      Peter   Sanders      M   10000      2      2020-10-03  Peter Sanders
1   2      Julie    Miller      F   12000      2      2020-01-14   Julie Miller
2   3     Rachel      Bray      F    9000      1      2020-09-03    Rachel Bray
3   4      Priti   Agarwal      F   10000      2      2020-01-03  Priti Agarwal
4   5      David       Cox      M    5000      1      2020-05-28      David Cox

SQL

在SQL中,我们首先需要添加新列:

%%sql

ALTER TABLE employee
ADD full_name varchar(40);
 * sqlite://
Done.
[]

接下来,我们使用SQL中的SET来设置该值。

%%sql

UPDATE employee
SET full_name = first_name || " " || last_name;
 * sqlite://
10 rows affected.
[]

“||”在SQLite中用作连接运算符。点此链接深入了解:https://www.sqlitetutorial.net/sqlite-string-functions/sqlite-concat/

结语

祝贺你!你现在已经了解了Pandas中最常见的SQL变换方法。

我已经努力做到面面俱到了,不过,我应该还是没能罗列齐全。

请批评指正!

一如既往,感谢你的阅读!

图片来自作者

你还可以订阅我们的YouTube频道,观看大量大数据行业相关公开课:https://www.youtube.com/channel/UCa8NLpvi70mHVsW4J_x9OeQ;在LinkedIn上关注我们,扩展你的人际网络!https://www.linkedin.com/company/dataapplab/

原文作者:Avi Chawla
翻译作者:高佑兮
美工编辑:过儿
校对审稿:Chuang
原文链接:https://towardsdatascience.com/pandas-isnt-enough-learn-these-25-pandas-to-sql-translations-to-upgrade-your-data-analysis-game-af8d0c26948d