将数据帧返回函数应用于基础数据帧的每一行
Applying dataframe-returning function to every row of base dataframe
玩具示例
假设 base_df
是如下所示的微型数据框:
In [221]: base_df
Out[221]:
seed
I S
0 a 0
b 1
1 a 2
b 3
请注意,base_df
的行有一个 2 级多索引。 (这里的部分问题涉及 "propagating" 这个多索引在派生数据框中的值。)
现在,函数 fn
(在本 post 末尾给出的定义)接受一个整数 seed
作为参数,returns 一个索引为 1 列的数据框通过字符串键1。例如:
In [222]: fn(0)
Out[222]:
F
key
01011 0.592845
10100 0.844266
In [223]: fn(1)
Out[223]:
F
key
11110 0.997185
01000 0.932557
11100 0.128124
我想生成一个新的数据帧,本质上是通过将 fn
应用于 base_df
的每一行,然后垂直连接生成的数据帧。更具体地说,所需的结果如下所示:
F
I S key
0 a 01011 0.592845
10100 0.844266
b 11110 0.997185
01000 0.932557
11100 0.128124
1 a 01101 0.185082
01110 0.931541
b 00100 0.070725
11011 0.839949
11111 0.121329
11000 0.569311
IOW,从概念上讲,通过为 base_df
的每一行生成一个 "sub-dataframe" 并垂直连接这些子数据帧来获得所需的数据帧。每行对应的子数据框有一个3级多索引。此多索引的前两个级别(I
和 S
)来自该行的 base_df
的多索引值,而其最后一个级别(key
) ,以及(单独的)F
列的值来自 fn
为该行的 seed
值返回的数据框。
我不清楚的部分是如何将行的原始多索引值传播到由 fn
为该行的 seed
值创建的数据帧的行。
重要提示: 我正在寻找一种方法来执行此操作,它与 base_df
的多索引级别的名称及其数量无关.
我尝试了以下方法
base_df.apply(lambda row: fn(row.seed), axis=1)
...但评估失败并出现错误
ValueError: Shape of passed values is (4, 2), indices imply (4, 1)
有什么方便的方法来做我想做的事情吗?
这是fn
的定义。就这个问题而言,它的内部结构并不重要。重要的是它需要一个整数 seed
作为参数,returns 一个数据帧,如前所述。
import numpy
def fn(seed, _spec='{{0:0{0:d}b}}'.format(5)):
numpy.random.seed(int(seed))
n = numpy.random.randint(2, 5)
r = numpy.random.rand(n)
k = map(_spec.format, numpy.random.randint(0, 31, size=n))
result = pandas.DataFrame(r, columns=['F'], index=k)
result.index.name = 'key'
return result
1 在这个例子中,这些键恰好对应于 0 到 31 之间的某个整数的二进制表示,包括在内,但这个事实不起作用在问题中。
选项 1
groupby
base_df.groupby(level=[0, 1]).apply(fn)
F
I S key
0 a 11010 0.385245
00010 0.890244
00101 0.040484
b 01001 0.569204
11011 0.802265
00100 0.063107
1 a 00100 0.947827
00100 0.056551
11000 0.084872
b 11110 0.592641
00110 0.130423
11101 0.915945
选项 2
pd.concat
pd.concat({t.Index: fn(t.seed) for t in base_df.itertuples()})
F
key
0 a 11011 0.592845
00011 0.844266
b 00101 0.997185
01111 0.932557
00000 0.128124
1 a 01011 0.185082
10010 0.931541
b 10011 0.070725
01010 0.839949
01011 0.121329
11001 0.569311
玩具示例
假设 base_df
是如下所示的微型数据框:
In [221]: base_df
Out[221]:
seed
I S
0 a 0
b 1
1 a 2
b 3
请注意,base_df
的行有一个 2 级多索引。 (这里的部分问题涉及 "propagating" 这个多索引在派生数据框中的值。)
现在,函数 fn
(在本 post 末尾给出的定义)接受一个整数 seed
作为参数,returns 一个索引为 1 列的数据框通过字符串键1。例如:
In [222]: fn(0)
Out[222]:
F
key
01011 0.592845
10100 0.844266
In [223]: fn(1)
Out[223]:
F
key
11110 0.997185
01000 0.932557
11100 0.128124
我想生成一个新的数据帧,本质上是通过将 fn
应用于 base_df
的每一行,然后垂直连接生成的数据帧。更具体地说,所需的结果如下所示:
F
I S key
0 a 01011 0.592845
10100 0.844266
b 11110 0.997185
01000 0.932557
11100 0.128124
1 a 01101 0.185082
01110 0.931541
b 00100 0.070725
11011 0.839949
11111 0.121329
11000 0.569311
IOW,从概念上讲,通过为 base_df
的每一行生成一个 "sub-dataframe" 并垂直连接这些子数据帧来获得所需的数据帧。每行对应的子数据框有一个3级多索引。此多索引的前两个级别(I
和 S
)来自该行的 base_df
的多索引值,而其最后一个级别(key
) ,以及(单独的)F
列的值来自 fn
为该行的 seed
值返回的数据框。
我不清楚的部分是如何将行的原始多索引值传播到由 fn
为该行的 seed
值创建的数据帧的行。
重要提示: 我正在寻找一种方法来执行此操作,它与 base_df
的多索引级别的名称及其数量无关.
我尝试了以下方法
base_df.apply(lambda row: fn(row.seed), axis=1)
...但评估失败并出现错误
ValueError: Shape of passed values is (4, 2), indices imply (4, 1)
有什么方便的方法来做我想做的事情吗?
这是fn
的定义。就这个问题而言,它的内部结构并不重要。重要的是它需要一个整数 seed
作为参数,returns 一个数据帧,如前所述。
import numpy
def fn(seed, _spec='{{0:0{0:d}b}}'.format(5)):
numpy.random.seed(int(seed))
n = numpy.random.randint(2, 5)
r = numpy.random.rand(n)
k = map(_spec.format, numpy.random.randint(0, 31, size=n))
result = pandas.DataFrame(r, columns=['F'], index=k)
result.index.name = 'key'
return result
1 在这个例子中,这些键恰好对应于 0 到 31 之间的某个整数的二进制表示,包括在内,但这个事实不起作用在问题中。
选项 1
groupby
base_df.groupby(level=[0, 1]).apply(fn)
F
I S key
0 a 11010 0.385245
00010 0.890244
00101 0.040484
b 01001 0.569204
11011 0.802265
00100 0.063107
1 a 00100 0.947827
00100 0.056551
11000 0.084872
b 11110 0.592641
00110 0.130423
11101 0.915945
选项 2
pd.concat
pd.concat({t.Index: fn(t.seed) for t in base_df.itertuples()})
F
key
0 a 11011 0.592845
00011 0.844266
b 00101 0.997185
01111 0.932557
00000 0.128124
1 a 01011 0.185082
10010 0.931541
b 10011 0.070725
01010 0.839949
01011 0.121329
11001 0.569311