Pandas 数据框 - lambda 演算和每个系列的最小值
Posted
技术标签:
【中文标题】Pandas 数据框 - lambda 演算和每个系列的最小值【英文标题】:Pandas data frame - lambda calculus and minimum value per series 【发布时间】:2016-01-22 03:31:59 【问题描述】:我有一个包含 3 列的 csv,count_id、AMV 和时间。
我正在使用 pandas 并将其作为数据框读入。
results= pd.read_csv('./output.csv')
首先,我首先为 count_id 排序数据帧,然后为 AMV 排序。
results_sorted = results.sort_index(by=['count_id','AMV'], ascending=[True, True])
这给了
count_id AMV Hour
0 16012E 4004 14
1 16012E 4026 12
2 16012E 4099 15
3 16012E 4167 11
4 16012E 4239 10
5 16012E 4324 13
6 16012E 4941 16
7 16012E 5088 17
8 16012E 5283 9
9 16012E 5620 8
10 16012E 5946 18
11 16012E 6146 7
12 16012W 3622 10
13 16012W 3904 12
14 16012W 3979 11
15 16012W 4076 9
16 16012W 4189 13
17 16012W 4870 14
18 16012W 4899 18
19 16012W 5107 15
20 16012W 5659 8
21 16012W 6325 7
22 16012W 6460 17
23 16012W 6500 16
我现在想对数据进行一些标准化,以便最终将其绘制在同一个图上。我想做的是找到每个系列的 AMV 的最小值(count_id),然后从给定的 AMV 中减去这个最小值。这会给我一个新列 AMV_norm。
看起来像:
count_id AMV Hour AMV_norm
0 16012E 4004 14 0
1 16012E 4026 12 22
2 16012E 4099 15 95
3 16012E 4167 11 163
4 16012E 4239 10 235
5 16012E 4324 13 320
6 16012E 4941 16 937
7 16012E 5088 17 1084
8 16012E 5283 9 1279
9 16012E 5620 8 1616
10 16012E 5946 18 1942
11 16012E 6146 7 2142
12 16012W 3622 10 0
13 16012W 3904 12 282
14 16012W 3979 11 357
15 16012W 4076 9 454
16 16012W 4189 13 567
17 16012W 4870 14 1248
18 16012W 4899 18 1277
19 16012W 5107 15 1485
20 16012W 5659 8 2037
21 16012W 6325 7 2703
22 16012W 6460 17 2838
23 16012W 6500 16 2878
如何定义找到每个系列的最小 AMV 值而不是总体 AMV 最小值的函数?它看起来像这样:
def minimum_series_value(AMV):
return AMV.argmin()
然后我需要创建一个新列并使用 lambda 函数填充该行。我知道它看起来像这样:
results_sorted['AMV_norm'] = results_sorted.apply(lambda row:results_sorted(row['AMV']))
【问题讨论】:
【参考方案1】:从变换最小值中减去 AMV 列:
In [11]: df.groupby('count_id')["AMV"].transform('min')
Out[11]:
0 4004
1 4004
2 4004
3 4004
4 4004
...
21 3622
22 3622
23 3622
dtype: int64
In [12]: df["AMV"] - df.groupby('count_id')["AMV"].transform('min')
Out[12]:
0 0
1 22
2 95
3 163
4 235
...
21 2703
22 2838
23 2878
dtype: int64
In [13]: df["AMV_norm"] = df["AMV"] - df.groupby('count_id')["AMV"].transform('min')
【讨论】:
【参考方案2】:我相信您想在count_id
上进行分组,然后计算该组的当前值与最小值之间的差值。
df['AMV_norm'] = (df.groupby('count_id').AMV
.transform(lambda group_series: group_series - np.min(group_series)))
>>> df
count_id AMV Hour AMV_norm
0 16012E 4004 14 0
1 16012E 4026 12 22
2 16012E 4099 15 95
3 16012E 4167 11 163
4 16012E 4239 10 235
5 16012E 4324 13 320
6 16012E 4941 16 937
7 16012E 5088 17 1084
8 16012E 5283 9 1279
9 16012E 5620 8 1616
10 16012E 5946 18 1942
11 16012E 6146 7 2142
12 16012W 3622 10 0
13 16012W 3904 12 282
14 16012W 3979 11 357
15 16012W 4076 9 454
16 16012W 4189 13 567
17 16012W 4870 14 1248
18 16012W 4899 18 1277
19 16012W 5107 15 1485
20 16012W 5659 8 2037
21 16012W 6325 7 2703
22 16012W 6460 17 2838
23 16012W 6500 16 2878
编辑: @AndyHayden 的方法稍微快一些:
%timeit df["AMV"] - df.groupby('count_id')["AMV"].transform('min')
1000 loops, best of 3: 736 µs per loop
%timeit df.groupby('count_id').AMV.transform(lambda x: x - np.min(x))
1000 loops, best of 3: 804 µs per loop
%timeit df.groupby('count_id').AMV.apply(lambda x: x - np.min(x))
1000 loops, best of 3: 1.32 ms per loop
【讨论】:
在转换中使用返回 Series 的 lambda 似乎很奇怪! (而不是使用应用。) 我猜他们使用相同的路径,但是 transform 通常意味着一个值分布在组上(例如 transform('min')),而 apply 意味着组可以返回任何东西。但你知道我不确定,这是我的理解。 有趣,谢谢。我更喜欢使用 lambda,但正如你所说,安迪的反应更快。感谢您的努力!以上是关于Pandas 数据框 - lambda 演算和每个系列的最小值的主要内容,如果未能解决你的问题,请参考以下文章
λ演算 (Lambda Calculus) 一 : 定义与函数式编程
如何将 lambda 函数正确应用到 pandas 数据框列