今天,我們要介紹一個用于數據操作的 Python 第三方庫 —— plydata,這個庫是基于 R 中的 dplyr、tidyr 和 forcats 包,許多函數名稱都是直接借用過來的
plydata 使用 >> 作為管道操作符,用于替代 ply(data, *verbs) 函數,目前隻支持 pandas 的 DataFrame 數據結構,後續可能還會添加對數據庫的支持
下面我們來看看怎麼使用 plydata 來玩轉數據操作吧
使用首先,使用 pip 進行安裝
pip install plydata
我們先舉個簡單的例子,先導入對應的模塊
import numpy as np
import pandas as pd
from plydata import define, query, if_else, ply
創建一個 DataFrame
df = pd.DataFrame({
'x': [0, 1, 2, 3],
'y': ['zero', 'one', 'two', 'three']}
)
使用 define 函數為數據框添加一列(或者使用 mutate 函數,兩者相同,對應于 tidyverse 中的同名函數)
In [5]: df
Out[5]:
x y
0 0 zero
1 1 one
2 2 two
3 3 three
In [6]: df >> define(z='x')
Out[6]:
x y z
0 0 zero 0
1 1 one 1
2 2 two 2
3 3 three 3
使用 if_else 來添加不同的值
In [7]: df >> define(z=if_else('x > 1', 1, 0))
Out[7]:
x y z
0 0 zero 0
1 1 one 0
2 2 two 1
3 3 three 1
與 R 中使用 tidyverse 包中的函數類似,也可以将數據框作為函數的第一個參數
In [8]: query(df, 'x > 1')
Out[8]:
x y
2 2 two
3 3 three
# 等同于下面的操作
In [9]: df >> query('x > 1')
Out[9]:
x y
2 2 two
3 3 three
或者使用 ply 函數代替管道操作,例如
In [10]: ply(df,
...: define(z=if_else('x > 1', 1, 0)),
...: query('z == 1')
...: )
Out[10]:
x y z
2 2 two 1
3 3 three 1
将每一次的操作作為參數,傳遞給 ply 函數
如果與 plotnine(基于 ggplot2 的 Python 實現)聯用,可以很容易将 R 的繪圖代碼,轉換為 Python。
例如,對于如下 R 代碼,繪制 sin(x) 函數在 [0,2] 區間的圖形
library(tidyverse)
tibble(x = seq(0, 2*pi, length.out = 500)) %>%
mutate(y = sin(x), sign = if_else(y >= 0, "positive", "negative")) %>%
ggplot(aes(x, y))
geom_line(aes(colour = sign), size = 1.5)
轉換為 Python 代碼
from plotnine import ggplot, aes, geom_line
(
pd.DataFrame({'x': np.linspace(0, 2*np.pi, 500)})
>> define(y='np.sin(x)')
>> define(sign=if_else('y >= 0', '"positive"', '"negative"'))
>> (ggplot(aes('x', 'y'))
geom_line(aes(color='sign'), size=1.5))
)
注意:在 Python 中,運算表達式都放置在引号内部,且字符串要表示為嵌套的引号
使用 call 函數為數據框執行外部函數或 pd.DataFrame 函數,例如,應用外部函數
In [11]: df = pd.DataFrame({
...: 'A': {0: 'a', 1: 'b', 2: 'c'},
...: 'B': {0: 1, 1: 3, 2: 5},
...: 'C': {0: 2, 1: 4, 2: np.nan}
...: })
In [12]: df >> call(pd.melt)
Out[12]:
variable value
0 A a
1 A b
2 A c
3 B 1
4 B 3
5 B 5
6 C 2.0
7 C 4.0
8 C NaN
In [13]: df >> call(pd.melt, id_vars=['A'], value_vars=['B'])
Out[13]:
A variable value
0 a B 1
1 b B 3
2 c B 5
應用對象方法
In [14]: df >> call('.dropna', axis=1)
Out[14]:
A B
0 a 1
1 b 3
2 c 5
In [15]: (df
...: >> call(pd.melt)
...: >> query('variable != "B"')
...: >> call('.reset_index', drop=True)
...: )
Out[15]:
variable value
0 A a
1 A b
2 A c
3 C 2.0
4 C 4.0
5 C NaN
單表操作主要包括如下函數
其功能都與 dplyr 包中的同名函數一樣
例如,mutate 函數添加列
In [16]: df >> mutate(x_sq = 'x**2')
Out[16]:
x x_sq
0 1 1
1 2 4
2 3 9
In [17]: df >> mutate(('x*2', 'x*2'), ('x*3', 'x*3'), x_cubed='x**3')
Out[17]:
x x*2 x*3 x_cubed
0 1 2 3 1
1 2 4 6 8
2 3 6 9 27
使用 arrange 函數對數據框進行排序
In [18]: df = pd.DataFrame({'x': [1, 5, 2, 2, 4, 0],
...: 'y': [1, 2, 3, 4, 5, 6]})
In [19]: df >> arrange('x')
Out[19]:
x y
5 0 6
0 1 1
2 2 3
3 2 4
4 4 5
1 5 2
In [20]: df >> arrange('x', '-y')
Out[20]:
x y
5 0 6
0 1 1
3 2 4
2 2 3
4 4 5
1 5 2
In [21]: df >> arrange('np.sin(y)')
Out[21]:
x y
4 4 5
3 2 4
5 0 6
2 2 3
0 1 1
1 5 2
使用 group_by 進行分組
In [22]: df = pd.DataFrame({'x': [1, 5, 2, 2, 4, 0, 4],
...: 'y': [1, 2, 3, 4, 5, 6, 5]})
In [23]: df >> group_by('x')
Out[23]:
groups: ['x']
x y
0 1 1
1 5 2
2 2 3
3 2 4
4 4 5
5 0 6
6 4 5
In [24]: df >> group_by('x') >> group_indices()
Out[24]: array([1, 4, 2, 2, 3, 0, 3])
類似于 define,group_by 可以添加新列
In [25]: df >> group_by('y-1', xplus1='x 1')
Out[25]:
groups: ['y-1', 'xplus1']
x y y-1 xplus1
0 1 1 0 2
1 5 2 1 6
2 2 3 2 3
3 2 4 3 3
4 4 5 4 5
5 0 6 5 1
6 4 5 4 5
如果後續的動詞未使用分組信息,則新産生的列将會保留在數據框中
In [26]: df >> group_by('y-1', xplus1='x 1') >> select('y')
Out[26]:
groups: ['y-1', 'xplus1']
y-1 xplus1 y
0 0 2 1
1 1 6 2
2 2 3 3
3 3 3 4
4 4 5 5
5 5 1 6
6 4 5 5
使用 query 來進行行過濾
In [27]: df = pd.DataFrame({'x': [0, 1, 2, 3, 4, 5],
...: 'y': [0, 0, 1, 1, 2, 3]})
In [28]: df >> query('x % 2 == 0')
Out[28]:
x y
0 0 0
2 2 1
4 4 2
In [29]: df >> query('x % 2 == 0 and y > 0')
Out[29]:
x y
2 2 1
4 4 2
In [30]: df >> query('x % 2 == 0 & y > 0')
Out[30]:
x y
2 2 1
4 4 2
In [31]: df >> group_by('y') >> query('x == x.min()')
Out[31]:
groups: ['y']
x y
0 0 0
2 2 1
4 4 2
5 5 3
使用 summarize 函數對數據進行統計
In [32]: df = pd.DataFrame({'x': [1, 5, 2, 2, 4, 0, 4],
...: 'y': [1, 2, 3, 4, 5, 6, 5],
...: 'z': [1, 3, 3, 4, 5, 5, 5]})
In [33]: df >> summarize('np.sum(x)', max='np.max(x)')
Out[33]:
np.sum(x) max
0 18 5
In [34]: df >> group_by('y', 'z') >> summarize(mean_x='np.mean(x)')
Out[34]:
y z mean_x
0 1 1 1.0
1 2 3 5.0
2 3 3 2.0
3 4 4 2.0
4 5 5 4.0
5 6 5 0.0
支持如下函數:
In [35]: df >> summarize('min(x)', 'max(x)', 'mean(x)', 'sum(x)',
...: 'first(x)', 'last(x)', 'nth(x, 3)')
Out[35]:
min(x) max(x) mean(x) sum(x) first(x) last(x) nth(x, 3)
0 0 5 2.571429 18 1 4 2
分組求值
In [36]: df >> group_by('y') >> summarize(y_count='n()')
Out[36]:
y y_count
0 1 1
1 2 1
2 3 1
3 4 1
4 5 2
5 6 1
In [37]: df >> group_by('y') >> summarize('mean(x)')
Out[37]:
y mean(x)
0 1 1.0
1 2 5.0
2 3 2.0
3 4 2.0
4 5 4.0
5 6 0.0
雙表操作主要包含:
與 dplyr 同名函數執行相同的功能。例如
In [38]: df1 = pd.DataFrame({
...: 'col1': ['one', 'two', 'three'],
...: 'col2': [1, 2, 3]
...: })
In [39]: df2 = pd.DataFrame({
...: 'col1': ['one', 'four', 'three'],
...: 'col2': [1, 4, 3]
...: })
In [40]: anti_join(df1, df2, on='col1')
Out[40]:
col1 col2
1 two 2
In [41]: outer_join(df1, df2, on='col1')
Out[41]:
col1 col2_x col2_y
0 one 1.0 1.0
1 two 2.0 NaN
2 three 3.0 3.0
3 four NaN 4.0
In [42]: inner_join(df1, df2, on='col1')
Out[42]:
col1 col2_x col2_y
0 one 1 1
1 three 3 3
In [43]: left_join(df1, df2, on='col1')
Out[43]:
col1 col2_x col2_y
0 one 1 1.0
1 two 2 NaN
2 three 3 3.0
In [44]: right_join(df1, df2, on='col1')
Out[44]:
col1 col2_x col2_y
0 one 1.0 1
1 four NaN 4
2 three 3.0 3
In [45]: semi_join(df1, df2, on='col1')
Out[45]:
col1 col2
0 one 1
2 three 3
In [48]: from plydata.tidy import *
In [49]: df = pd.DataFrame({
...: 'name': ['mary', 'oscar', 'martha', 'john'],
...: 'math': [92, 83, 85, 90],
...: 'art': [75, 95, 80, 72]
...: })
In [50]: df >> gather('subject', 'grade', ['math', 'art'])
Out[50]:
name subject grade
0 mary math 92
1 oscar math 83
2 martha math 85
3 john math 90
4 mary art 75
5 oscar art 95
6 martha art 80
7 john art 72
In [51]: df = pd.DataFrame({
...: 'name': ['mary', 'mary', 'john', 'john'],
...: 'city':['dakar', 'dakar', 'lome', 'lome'],
...: 'year': [1990, 1992, 1996, 1998],
...: 'data_t1_sunny': [8, 6, 4, 7],
...: 'data_t2_rainy': [9, 7, 7, 6]
...: })
In [52]: df >> pivot_longer(
...: cols=select(startswith='data'),
...: names_to=['take', 'season'],
...: values_to='score',
...: names_pattern=r'data_(t\d)(_\w )',
...: names_prefix={'take': 't', 'season': '_'}
...: )
Out[52]:
name city year take season score
0 mary dakar 1990 1 sunny 8
1 mary dakar 1992 1 sunny 6
2 john lome 1996 1 sunny 4
3 john lome 1998 1 sunny 7
4 mary dakar 1990 2 rainy 9
5 mary dakar 1992 2 rainy 7
6 john lome 1996 2 rainy 7
7 john lome 1998 2 rainy 6
In [53]: df = pd.DataFrame({
...: 'name': ['mary', 'oscar', 'martha', 'john'] * 2,
...: 'initials': ['M.K', 'O.S', 'M.J', 'J.T'] * 2,
...: 'subject': np.repeat(['math', 'art'], 4),
...: 'grade': [92, 83, 85, 90, 75, 95, 80, 72],
...: 'midterm': [88, 83, 89, 93, 85, 95, 76, 79]
...: })
In [54]: df >> pivot_wider(
...: names_from='subject',
...: values_from=('grade', 'midterm')
...: )
Out[54]:
initials name grade_art grade_math midterm_art midterm_math
0 J.T john 72 90 79 93
1 M.J martha 80 85 76 89
2 M.K mary 75 92 85 88
3 O.S oscar 95 83 95 83
In [55]: df = pd.DataFrame({
...: 'name': ['mary', 'oscar', 'martha', 'john'] * 2,
...: 'subject': np.repeat(['math', 'art'], 4),
...: 'grade': [92, 83, 85, 90, 75, 95, 80, 72]
...: })
In [56]: df >> spread('subject', 'grade')
Out[56]:
name art math
0 john 72 90
1 martha 80 85
2 mary 75 92
3 oscar 95 83
In [57]: df = pd.DataFrame({
...: 'parent': ['martha', 'james', 'alice'],
...: 'child': ['leah', 'joe,vinny,laura', 'pat,lee'],
...: 'age': ['3', '12,6,4', '2,7']
...: })
In [58]: df >> separate_rows('child', 'age')
Out[58]:
parent child age
0 martha leah 3
1 james joe 12
2 james vinny 6
3 james laura 4
4 alice pat 2
5 alice lee 7
plydata 還提供了很多函數用于處理分類變量,我們就不再一一說明了,感興趣的可以通過查閱下面的文檔來學習,每個函數都有對應的例子,清晰易懂
https://plydata.readthedocs.io/en/stable/api.html
,更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!