首先我要说的是,我对 pandas 还很陌生,所以我可能缺少一个非常简单的解决方案。我有一个包含 61 列的 DataFrame,第一列是主题,接下来的 60 列对应于 60 次试验。每列都有每次试验的时间值。 这是我的数据示例(只有 4 列的较短版本):
import pandas as pd
df = pd.DataFrame([[1, 1, 1, 1], [2, 1, 2, 2], [3, 1, 3, 3], [4, 1, 4, 4], [5, 1, 5, 5]], columns = ['Subject', 'trial1', 'trial2', 'trial3'])
subjects = ([1, 2, 3, 4, 5])
我想获得所有行和所有试验的 x 次试验的时间总和,我使用以下代码:
MyColumns = ['time', 'subject', 'trial']
sum_of_times = pd.DataFrame(columns=MyColumns)
for subject in subjects:
for trial in range(1, 3):
MyRow = df.loc[df['Subject'] == subject].index
time = df.iloc[MyRow, 1:(trial+1)].sum(axis=1)
new_row = [time, subject, trial]
sum_of_times.loc[len(sum_of_times)] = new_row
sum_of_times = sum_of_times.reset_index(drop=True)
sum_of_times
因此,例如,如果我要进入试验 2,我希望得到:
time subject trial
0 1 1 1
1 2 1 2
2 1 2 1
3 3 2 2
4 1 3 1
5 4 3 2
6 1 4 1
7 5 4 2
8 1 5 1
9 6 5 2
地点:
等等。 (我在这里添加了_,这样更容易阅读)。
我遇到的问题是,我在
time
中获得了正确的数值,但我还从原始 DataFrame (df
) 和 dtype 中获取了行索引。这是输出(我找不到正确复制和粘贴的方法):
time subject trial
0 0 1 dtype: int64 1 1
1 0 2 dtype: int64 1 2
2 1 1 dtype: int64 2 1
3 1 3 dtype: int64 2 2
4 2 1 dtype: int64 3 1
5 2 4 dtype: int64 3 2
6 3 1 dtype: int64 4 1
7 3 5 dtype: int64 4 2
8 4 1 dtype: int64 5 1
9 4 6 dtype: int64 5 2
有没有办法可以只选择数值?
假设没有重复的
Subject
s
您可以将 squeeze
time
用作标量。
但是,您正在执行的操作是累积和,如果您先清理数据,则有更简单的方法可以做到这一点。我将使用
wide_to_long()
将 trial{n}
列更改为一列 trial
数字和一列 time
s:
long = (
pd.wide_to_long(df, "trial", i="Subject", j="_trial")
.rename(columns={"trial": "time"})
.rename_axis(index={"_trial": "trial"})
.sort_index()
)
time
Subject trial
1 1 1
2 1
3 1
... ...
5 1 1
2 5
3 5
[15 rows x 1 columns]
然后您需要做的就是按
Subject
和 .cumsum()
进行分组。
result = long.groupby(level="Subject").cumsum()
您说过您想要“所有试验”的总和,所以这是完整的结果。如果需要多索引切片,您可以选择块,例如前两次试验:
ix = pd.IndexSlice
result.loc[ix[:, 1:2], :]
time
Subject trial
1 1 1
2 2
2 1 1
2 3
3 1 1
2 4
4 1 1
2 5
5 1 1
2 6
.unstack()
以密集表格形式查看结果,类似于输入。
result.unstack('trial')
time
trial 1 2 3
Subject
1 1 2 3
2 1 3 5
3 1 4 7
4 1 5 9
5 1 6 11