原文:10 Tips And Tricks For Data Scientists Vol.3[1]
译者:赵西西
原博客简介:Predictive Hacks是与数据科学相关的一切的在线资源中心。该博客由一群数据科学家所运营,专注于讲解在各种领域如何使用大数据技术(从机器学习和人工智能到业务领域)。
前面已经介绍了一些数据分析的技巧,主要是用Python和R实现。具体内容可见:翻译|给数据科学家的10个提示和技巧Vol.1;翻译|给数据科学家的10个提示和技巧Vol.1;翻译|记住一些常用的R包;翻译|R用于研究,Python用于生产。
两个数据框,如下:
df1 = data.frame(x11 = c(10,20,30,40,50,55,60),
x12 = c(11,15,20,30,35,60,70)
)
df2 = data.frame(x21 = c(100,150,200,250,300,400,500),
x22 = c(110,150,180,250,300,400,600)
)
接着,直接利用cor()
函数即可得到相关系数矩阵,矩阵的第一个元素表示x11和x21之间的相关程度,其他元素含义类似:
> cor(df1,df2)
x21 x22
x11 0.9538727 0.9000503
x12 0.9889076 0.9755973
在SQL中,Count(Case When … Else … End)
是一个使用频率非常高的计数语句。现在通过一个例子来说明如何在dplyr中实现同样的操作:
library(sqldf)
library(dplyr)
df<-data.frame(id = 1:10,
gender = c("m","m","m","f","f","f","m","f","f","f"),
amt= c(5,20,30,10,20,50,5,20,10,30))
df
> df
id gender amt
1 1 m 5
2 2 m 20
3 3 m 30
4 4 f 10
5 5 f 20
6 6 f 50
7 7 m 5
8 8 f 20
9 9 f 10
10 10 f 30
要想获得不同的列中每个性别的人数和总和, 在R中利用SQL语句实现的方法如下,需要用到sqldf
包:
> sqldf("select count(case when gender='m' then id else null end) as male_cnt,
count(case when gender='f' then id else null end) as female_cnt,
sum(case when gender='m' then amt else 0 end) as male_amt,
sum(case when gender='f' then amt else 0 end) as female_amt
from df")
male_cnt female_cnt male_amt female_amt
1 4 6 60 140
>
利用dpylr
实现的方法如下,对每一列设置相应的条件进行选择,例如id[gender=="m"]
就是在id列中找出male的数据并形成一个子集:
> df%>%summarise(male_cnt=length(id[gender=="m"]),
female_cnt=length(id[gender=="f"]),
male_amt=sum(amt[gender=="m"]),
female_amt=sum(amt[gender=="f"])
)
male_cnt female_cnt male_amt female_amt
1 4 6 60 140
一个pandas的DataFrame,其中一个列是JSON格式的,此时希望提取特定的信息。我们使用Kaggle中的doc_report.csv数据集来示范:
import pandas as pd
import ast
pd.set_option("max_colwidth", 180)
doc = pd.read_csv("doc_reports.csv", index_col=0)
# print the properties column
doc['properties']
查看数据发现有JSON格式的字段,此时需要将其转换为字典,再提取所需的信息。先利用ast
库将其转换为一个字典,然后为每个键创建单独的列,如下所示:
dummy = doc['properties'].apply(lambda x: ast.literal_eval(x))
doc['gender'] = dummy.apply(lambda x:x.get('gender'))
doc['nationality'] = dummy.apply(lambda x:x.get('nationality'))
doc['document_type'] = dummy.apply(lambda x:x.get('document_type'))
doc['date_of_expiry'] = dummy.apply(lambda x:x.get('date_of_expiry'))
doc['issuing_country'] = dummy.apply(lambda x:x.get('issuing_country'))
# lets get the columns
doc[['gender', 'nationality', 'document_type', 'date_of_expiry','issuing_country' ]]
通过一个示例演示如何使用applymap()
函数更改pandas数据框中的多个列值。假设DataFrame的值是1、2和3,你想应用下面的映射函数:
df = pd.DataFrame({'A':[1,1,2,2,3,3],
'B':[1,2,3,1,2,3]})
df
A B
0 1 1
1 1 2
2 2 3
3 2 1
4 3 2
5 3 3
首先根据映射函数创建字典,再对每一列应用applymap()
函数:
# 创建映射字典
d = {1 : 0, 2: 1, 3: 1}
# 对每一列应用函数
df.applymap(d.get)
A B
0 0 0
1 0 1
2 1 1
3 1 0
4 1 1
5 1 1
利用plotly.express[2],可以很容易地创建漂亮的树形图。假设我们想要研究各国的预期寿命,同时还要考虑到大陆和该国的人口。在下面的树图中,矩形的大小代表人口,颜色代表寿命。预期寿命越长,颜色越蓝。预期寿命越低,颜色越红。
import plotly.express as px
import numpy as np
df = px.data.gapminder().query("year == 2007")
df["world"] = "world" # in order to have a single root node
fig = px.treemap(df, path=['world', 'continent', 'country'], values='pop',
color='lifeExp', hover_data=['iso_alpha'],
color_continuous_scale='RdBu',
color_continuous_midpoint=np.average(df['lifeExp'], weights=df['pop']))
fig.show()
和前面R中的做法类似,python中利用的是corr()
函数:
df1 = pd.DataFrame({'x11' : [10,20,30,40,50,55,60],
'x12' : [11,15,20,30,35,60,70]})
df2 = pd.DataFrame({'x21' : [100,150,200,250,300,400,500],
'x22' : [110,150,180,250,300,400,600]})
pd.concat([df1, df2], axis=1, keys=['df1', 'df2']).corr().loc['df1', 'df2']
x21 x22
x11 0.953873 0.900050
x12 0.988908 0.975597
只需输入:
(df=='a').any()
A True
B False
C True
假设有这样一组数据:
import pandas as pd
df = pd.DataFrame({'MyDate': ['2020-03-11', '2021-04-26', '2021-01-17']})
df['MyDate'] = pd.to_datetime(df.MyDate)
df
MyDate
0 2020-03-11
1 2021-04-26
2 2021-01-17
而你需要把该日期还原到当月的第一天:
df['Truncated'] = df['MyDate'] + pd.offsets.MonthBegin(-1)
# OR
# df['Truncated'] = df['MyDate'] - pd.offsets.MonthBegin(1)
df
MyDate Truncated
0 2020-03-11 2020-03-01
1 2021-04-26 2021-04-01
2 2021-01-17 2021-01-01
当一个特定的文件夹中有多个CSV文件,此时我们想将它们存储到一个pandas数据框中。假设CSV文件位于My_Folder下:
import os
import pandas as pd
# 创建一个空的数据框
df = pd.DataFrame()
# 遍历 My_Folder中的所有文件
for file in os.listdir("My_Folder"):
if file.endswith(".csv"):
df = pd.concat([df , pd.read_csv(os.path.join("My_Folder", file))], axis=0 )
# 将索引重置
df.reset_index(drop=True, inplace=True)
df
现在df包含了My_Folder中的CSV文件。
当一个特定文件夹中有多个CSV文件,此时想将它们连接起来并保存到一个名为merged.csv的文件中。我们可以利用pandas,并在.to_csv()
中使用mode=a
参数,该参数的含义是追加:
import os
import pandas as pd
# 遍历 My_Folder中的所有文件
for file in os.listdir("My_Folder"):
if file.endswith(".csv"):
tmp = pd.read_csv(os.path.join("My_Folder", file))
tmp.to_csv("merged.csv", index=False, header=False, mode='a')
当有多个txt文件,此时想将所有这些文件连接到一个txt文件中。假设txt文件位于dataset文件夹中,首先需要获取这些文件的路径:
import os
# 在文件夹中找到所有文件
inputs = []
for file in os.listdir("dataset"):
if file.endswith(".txt"):
inputs.append(os.path.join("dataset", file))
# 将所有文件连接到 merged_file.txt中
with open('merged_file.txt', 'w') as outfile:
for fname in inputs:
with open(fname, encoding="utf-8", errors='ignore') as infile:
outfile.write(infile.read())
通过上面的代码,成功地将所有这些文件连接到一个名为merged_file.txt的文件中。在文件比较大的情况下,可以进行如下操作:
with open('merged_file.txt', 'w') as outfile:
for fname in inputs:
with open(fname, encoding="utf-8", errors='ignore') as infile:
for line in infile:
outfile.write(line)
[1]
10 Tips And Tricks For Data Scientists Vol.3: https://predictivehacks.com/10-tips-and-tricks-for-data-scientists-vol-3/
[2]
plotly.express: https://plotly.com/python/plotly-express/