Pandas:Apply():返回多个值
我的数据是以年份为基础的,年份作为索引。我有一个叫做someFunc()的函数,它对分组后的数据进行一些操作。不过,这个函数会返回两个值(两个浮点数,而不是列)。我想把这两个值放到旧数据框中的两个新列里。为了演示,我想用一个简单的函数来说明:
def someFunc(group):
a = 1
b = 2
return pd.DataFrame([[a, b]], columns={'colA', 'colB'}, index=[group['year'][0]])
results = df.groupby(level=0).apply(someFunc)
pd.merge(df, results, left_index=True, right_index=True)
但是,这样会产生一个双重索引的值:一个是因为我添加了索引,另一个是来自apply()的索引:
results
colA colB
year
1961 1961 1 2
1962 1962 1 2
1963 1963 1 2
因此,合并就无法正常工作。我尝试了其他各种方法(包括返回numpy数组),但都不太好用。我该怎么办呢?我知道我可以把这个函数拆分开,分别运行两次代码,针对每一列 - 但这样效率不高。为了更清楚,我期望的结果(对于变量result)是:
results
colA colB
year
1961 1 2
1962 1 2
1963 1 2
在此之前,数据看起来是这样的:
c a b
year
1983 722 1001 1.06300
1984 722 1001 1.24225
1985 722 1001 2.78925
1986 722 1001 0.59600
1982 442110 1003 1.86300
中间结果
return pd.DataFrame([[a, b]], columns=['colA', 'colB'], index=[group['year'].max()])
返回:
colA colB
1961 30 2.434379
所以这就是关键问题,对吧?它返回了一个带索引的东西,然后apply()
又在上面叠加了自己的索引。由于没有办法返回一个没有索引的数据框,我猜解决方案应该在影响apply()
上。
解决方案
正如在某个评论中提到的:
results = df.groupby(level=0).apply(someFunc).reset_index(level=0, drop=True)
1 个回答
1
这段代码在使用你的数据时对我有效。
In [57]:
temp="""year c a b
1983 722 1001 1.06300
1984 722 1001 1.24225
1985 722 1001 2.78925
1986 722 1001 0.59600
1982 442110 1003 1.86300 """
df = pd.read_csv(io.StringIO(temp), sep='\s+')
df
Out[57]:
year c a b
0 1983 722 1001 1.06300
1 1984 722 1001 1.24225
2 1985 722 1001 2.78925
3 1986 722 1001 0.59600
4 1982 442110 1003 1.86300
[5 rows x 4 columns]
In [66]:
def someFunc(group):
a = 1
b = 2
#print(group['year'].values)
return pd.DataFrame([[a, b]], columns={'colA', 'colB'}, index=[group['year'].max()])
df.groupby(level=0).apply(someFunc)
Out[66]:
colA colB
0 1983 1 2
1 1984 1 2
2 1985 1 2
3 1986 1 2
4 1982 1 2
[5 rows x 2 columns]
编辑
经过进一步讨论,上面的代码也显示了你遇到的重复索引问题,所以你可以使用 reset_index
来消除重复。
In [91]:
def someFunc(group):
a = 1
b = 2
return pd.DataFrame([[a, b]], columns={'colA', 'colB'}, index=[group['year'].max()])
df.groupby(level=0).apply(someFunc).reset_index(level=0, drop=True)
Out[91]:
colA colB
1983 1 2
1984 1 2
1985 1 2
1986 1 2
1982 1 2
[5 rows x 2 columns]