我是Python和Pandas的新手。我想为列Opt_1至Opt_7的每一行找到最常见的项目。请注意,出于某些原因,某些空白单元格似乎具有NaN,而在其他情况下,其空白为None。
ID Col_1 Col_2 Opt_1 Opt_2 Opt_3 Opt_4 Opt_5 Opt_6 Opt_7
1 Game 1 Team 1 13
2 Game 1 Team 2 -13
3 Game 1 Team 1
4 Game 1 Team 2
5 Game 2 Team 1 -7.5 -7.5 -7.5 -7.5
6 Game 2 Team 2 7.5 7.5 7.5 7.5
7 Game 2 Team 1 -2.5 -1.5
8 Game 2 Team 2 2.5 1.5
9 Game 3 Team 1 3.5 3.5
10 Game 3 Team 2 -3.5 -3.5
11 Game 3 Team 1 -1 -1.5 -1
12 Game 3 Team 2 1 1.5 1
我已经尝试了以下代码,该代码对于大多数行(并非全部)都能按预期工作。而且有点慢。
def freq_value(series):
return Counter(series).most_common()[0][0]
for row in df.iterrows():
df['result'] = df.apply(lambda row: freq_value((row['Opt_1'], row['Opt_2'], row['Opt_3'], row['Opt_4'], row['Opt_5'], row['Opt_6'], row['Opt_7'])), axis=1)
以下是预期结果和实际结果:
ID Expected Actual Result
1 NaN NaN
2 NaN NaN
3 NaN NaN
4 NaN NaN
5 -7.5 -7.5
6 7.5 7.5
7 NaN NaN
8 NaN NaN
9 3.5 3.5
10 -3.5 -3.5
11 -1 NaN
12 1 NaN
是否有这样做的方法,所以它是100%正确的,并且可能不需要一次又一次遍历每一行吗?预先感谢您的任何建议。
答案 0 :(得分:0)
>>> import numpy as np
>>> import pandas as pd
>>> df = pd.DataFrame({
... 'ID': range(1, 13),
... 'Col_1': [*(['Game 1'] * 4), *(['Game 2'] * 4), *(['Game 3'] * 4)],
... 'Col_2': ['Team 1', 'Team 2'] * 6,
... 'Opt_1': [13, -13, np.nan, np.nan, -7.5, 7.5, np.nan, np.nan, np.nan, np.nan, -1, 1],
... 'Opt_2': [np.nan, np.nan, np.nan, np.nan, -7.5, 7.5, -2.5, 2.5, 3.5, -3.5, -1.5, 1.5],
... 'Opt_3': [np.nan, np.nan, np.nan, np.nan, -7.5, 7.5, -1.5, 1.5, 3.5, -3.5, -1, 1],
... 'Opt_4': [np.nan, np.nan, np.nan, np.nan, -7.5, 7.5, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan],
... 'Opt_5': [np.nan] * 12,
... 'Opt_6': [np.nan] * 12,
... 'Opt_7': [np.nan] * 12
... })
>>> df
ID Col_1 Col_2 Opt_1 Opt_2 Opt_3 Opt_4 Opt_5 Opt_6 Opt_7
0 1 Game 1 Team 1 13.0 NaN NaN NaN NaN NaN NaN
1 2 Game 1 Team 2 -13.0 NaN NaN NaN NaN NaN NaN
2 3 Game 1 Team 1 NaN NaN NaN NaN NaN NaN NaN
3 4 Game 1 Team 2 NaN NaN NaN NaN NaN NaN NaN
4 5 Game 2 Team 1 -7.5 -7.5 -7.5 -7.5 NaN NaN NaN
5 6 Game 2 Team 2 7.5 7.5 7.5 7.5 NaN NaN NaN
6 7 Game 2 Team 1 NaN -2.5 -1.5 NaN NaN NaN NaN
7 8 Game 2 Team 2 NaN 2.5 1.5 NaN NaN NaN NaN
8 9 Game 3 Team 1 NaN 3.5 3.5 NaN NaN NaN NaN
9 10 Game 3 Team 2 NaN -3.5 -3.5 NaN NaN NaN NaN
10 11 Game 3 Team 1 -1.0 -1.5 -1.0 NaN NaN NaN NaN
11 12 Game 3 Team 2 1.0 1.5 1.0 NaN NaN NaN NaN
>>> opts = ['Opt_{}'.format(i) for i in range(1, 8)]
>>> df[opts].mode(axis=1, dropna=False)
0
0 NaN
1 NaN
2 NaN
3 NaN
4 -7.5
5 7.5
6 NaN
7 NaN
8 NaN
9 NaN
10 NaN
11 NaN
答案 1 :(得分:0)
使用filter
选择列,使用mode
+ mask
查找唯一模式:
(df.filter(like='Opt')
.mode(axis=1)
.set_axis(['a', 'b'], axis=1, inplace=False)
.eval('a.mask(b.notna())', engine='python'))
0 13.0
1 -13.0
2 NaN
3 NaN
4 -7.5
5 7.5
6 NaN
7 NaN
8 3.5
9 -3.5
10 -1.0
11 1.0
Name: a, dtype: float64
mode
将为给定的行返回 all 模式。这意味着,如果有两个频率相等的值,则输出中将有两列。上面的解决方案可以处理最多两列的情况。
如果模式是唯一的,则解决方案可以简化为
df.filter(like='Opt').mode(axis=1).iloc[:, 0]
当没有唯一模式时的另一种解决方案,它将推广到输出中任意数量的列。
u = df.filter(like='Opt').mode(axis=1)
if len(u.columns) > 1:
u = u.iloc[:, 0].where(u.iloc[:, 1:].isna().all(axis=1))
u
0 13.0
1 -13.0
2 NaN
3 NaN
4 -7.5
5 7.5
6 NaN
7 NaN
8 3.5
9 -3.5
10 -1.0
11 1.0
Name: 0, dtype: float64