对不起,我的解释很繁重,但希望您能理解。
我是R使用者,我发现数据整理中的tidyverse功能非常强大。但是最近我开始学习Python,尤其是熊猫,以扩展我的数据分析机会。本能地,我试图像在使用dplyr时那样去做熊猫。
所以我的问题是,在熊猫中使用方法链接时,是否与dplyr点等效。
这里示例说明了从每个组中大于test_df ['data']中当前值的所有值计算最小值,并且比相同计算但跨新列的最小值计算。
R的示例:
require(dplyr)
require(purrr)
test_df = data.frame(group = rep(c(1,2,3), each = 3),
data= c(1:9))
test_df %>%
group_by(group) %>%
mutate(., min_of_max = map_dbl(data, ~data[data > .x] %>% min())) %>%
mutate(., min_of_max_2 = map_dbl(min_of_max, ~min_of_max[min_of_max > .x] %>% min()))
输出:
# A tibble: 9 x 4
# Groups: group [3]
group data min_of_max min_of_max_2
<dbl> <int> <dbl> <dbl>
1 1 1 2 3
2 1 2 3 Inf
3 1 3 Inf Inf
4 2 4 5 6
5 2 5 6 Inf
6 2 6 Inf Inf
7 3 7 8 9
8 3 8 9 Inf
9 3 9 Inf Inf
我知道dplyr甚至不需要点,但为了更好地理解我的问题的具体含义,我把它放在了句点
在熊猫中做同样的事情
无效示例:
import pandas as pd
import numpy as np
test_df = (
pd.DataFrame({'A': np.array([1,2,3]*3), 'B': np.array(range(1,10))})
.sort_values(by = ['A', 'B'])
)
(test_df.assign(min_of_max = test_df.apply(lambda x: (test_df.B[(test_df.B > x.B) &
(test_df.A[test_df.A == x.A])]).min(), axis = 1))
.assign(min_of_max2 = 'assume_dot_here'.apply(lambda x: (test_df.min_of_max[(test_df.min_of_max > x.min_of_max) &
(test_df.A[test_df.A == x.A])]).min(), axis = 1)))
在此示例中,将点放在第二个.assign
中将是很好的功能,但在熊猫中不起作用。
有效示例,它破坏了链:
test_df = test_df.assign(min_of_max = test_df.apply(lambda x:
(test_df.B[(test_df.B > x.B) & (test_df.A[test_df.A == x.A])]).min(), axis = 1))
test_df = test_df.assign(min_of_max2 = test_df.apply(lambda x :
(test_df.min_of_max[(test_df.min_of_max > x.min_of_max) & (test_df.A[test_df.A
== x.A])]).min(), axis = 1))
输出:
A B min_of_max min_of_max2
0 1 1 4.0 7.0
3 1 4 7.0 NaN
6 1 7 NaN NaN
1 2 2 5.0 8.0
4 2 5 8.0 NaN
7 2 8 NaN NaN
2 3 3 6.0 9.0
5 3 6 9.0 NaN
8 3 9 NaN NaN
因此,在第二个.assign
中是否有任何便捷的方法可以从链的前一部分调用对象?由于第二秒使用test_df.apply()
。赋值将采用初始test_df而不计算test_df['min_of_max']
很抱歉,Python中的代码有些难以理解,我仍在弄清楚如何写得更清晰。
在Pandas中,运行两个assign
调用的链,但是以任何不依赖原始数据帧上下文的方式进行,例如,使用DataFrame.apply
调用。下面使用跨索引值的列表理解等效项:
test_df = pd.DataFrame({'group': np.repeat([1,2,3],3), 'data': np.arange(1,10)})
(
test_df.assign(min_of_max = lambda x: [np.min(x["data"].loc[(x["data"] > x["data"].iloc[i]) &
(x["group"] == x["group"].iloc[i])]
) for i in test_df.index.values])
.assign(min_of_max_2 = lambda x: [np.min(x["min_of_max"].loc[(x["min_of_max"] > x["min_of_max"].iloc[i]) &
(x["group"] == x["group"].iloc[i])]
) for i in test_df.index.values])
)
# group data min_of_max min_of_max_2
# 0 1 1 2.0 3.0
# 1 1 2 3.0 NaN
# 2 1 3 NaN NaN
# 3 2 4 5.0 6.0
# 4 2 5 6.0 NaN
# 5 2 6 NaN NaN
# 6 3 7 8.0 9.0
# 7 3 8 9.0 NaN
# 8 3 9 NaN NaN
但是,就像可以在dplyr::mutate
中组合分配一样,也可以通过使用DataFrame.assign
方法组合DataFrame.assign
调用来进行相同的操作(不要与lambda
中的lambda
混淆)。
R
DataFrame.apply
Pandas
test_df <- data.frame(group = rep(c(1,2,3), each = 3), data = c(1:9))
test_df %>%
group_by(group) %>%
mutate(min_of_max = map_dbl(data, ~data[data > .x] %>% min()),
min_of_max_2 = map_dbl(min_of_max, ~min_of_max[min_of_max > .x] %>% min()))
# # A tibble: 9 x 4
# # Groups: group [3]
# group data min_of_max min_of_max_2
# <dbl> <int> <dbl> <dbl>
# 1 1 1 2 3
# 2 1 2 3 Inf
# 3 1 3 Inf Inf
# 4 2 4 5 6
# 5 2 5 6 Inf
# 6 2 6 Inf Inf
# 7 3 7 8 9
# 8 3 8 9 Inf
# 9 3 9 Inf Inf
顺便说一下,由于熊猫可疑是Wes McKinney在多年前根据R建模的(请参阅test_df = pd.DataFrame({'group': np.repeat([1,2,3],3), 'data': np.arange(1,10)})
test_df.assign(min_of_max = lambda x: [np.min(x["data"].loc[(x["data"] > x["data"].iloc[i]) &
(x["group"] == x["group"].iloc[i])]
) for i in test_df.index.values],
min_of_max_2 = lambda x: [np.min(x["min_of_max"].loc[(x["min_of_max"] > x["min_of_max"].iloc[i]) &
(x["group"] == x["group"].iloc[i])]
) for i in test_df.index.values])
# group data min_of_max min_of_max_2
# 0 1 1 2.0 3.0
# 1 1 2 3.0 NaN
# 2 1 3 NaN NaN
# 3 2 4 5.0 6.0
# 4 2 5 6.0 NaN
# 5 2 6 NaN NaN
# 6 3 7 8.0 9.0
# 7 3 8 9.0 NaN
# 8 3 9 NaN NaN
),所以基数R倾向于对熊猫更易翻译。下面,paper镜像了within
和assign
镜像列表理解的用法。
Base R
sapply
猜猜我已经找到了使用lambda函数在链的上一部分中引用对象的简要方法。将其传递给带有x参数的assign将把x视为来自链的上一部分的数据帧。
test_df <- within(test_df, {
min_of_max <- sapply(1:nrow(test_df),
function(i) min(data[data > data[i] &
group == group[i]]))
min_of_max_2 <- sapply(1:nrow(test_df),
function(i) min(min_of_max[min_of_max > min_of_max[i] &
group == group[i]]))
})
test_df[c("group", "data", "min_of_max", "min_of_max_2")]
# group data min_of_max min_of_max_2
# 1 1 1 2 3
# 2 1 2 3 Inf
# 3 1 3 Inf Inf
# 4 2 4 5 6
# 5 2 5 6 Inf
# 6 2 6 Inf Inf
# 7 3 7 8 9
# 8 3 8 9 Inf
# 9 3 9 Inf Inf
在第二个.assign中传递'lambda y'将把y作为来自链中先前部分的输出