Pandas:根据年份对数据框应用不同的过滤器
Pandas: Apply different filter to dataframe based on the year
如果年份高于或低于某个范围,我想对我的数据框应用不同的过滤器。这是数据框
dataset=pd.DataFrame({'ID': [1,1,1,2,2,2,3,3,3,4,4,4,5,5,5],
'Avail' : [2017,2017,2017,2018,2018,2018,2017,2017,2017,2017,2017,2017,2017,2018,2018],
'Change' : [0,0,2018,0,0,0,0,0,0,0,0,0,2018,0,0],
'Pref' : [1,2,3,1,2,3,1,2,3,1,2,3,1,2,3],
'Status': ['null', 'null','Q','null','null','null','Q','null','null','null','null','null','Q','null','null']
},columns=['ID', 'Avail', 'Change', 'Pref', 'Status'])
这是我编写的产生错误的代码:
def yearfilt(x):
if x.loc[:, ['Avail', 'Change']].values.max(axis=1) < 2018:
if pd.isnull(x.Status):
x.drop_duplicates(subset=['STU_ID','Status' ], keep='last')
else:
x=x.drop(x[pd.isnull(x.Status)].index)
else:
if pd.isnull(x.ASSESSMENT_OUTCOME_CD):
x.drop_duplicates(subset=['STU_ID','Status' ], keep='first')
else:
x=x.drop(x[pd.isnull(x.Status)].index)
df=dataset.groupby(['ID']).apply(yearfilt).sort_values(["ID"]).reset_index(drop=True)
错误是
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
我想执行的是:
If the max (Avail, Change) < 2018 then
Case 1: the same status --> drop duplicates and keep the last
Case 2: different status --> drop null-value statuses
else (in other words max (Avail, Change) = 2018)
Case 1: the same status --> drop duplicates and keep the first
Case 2: different status --> drop null-value statuses
输出应如下所示:
ID Year Change Pref Status
1 2017 2018 3 Q
2 2018 0 1 null
3 2017 0 1 Q
4 2017 0 3 null
5 2017 2018 1 Q
基本上,每个 ID 我只想保留一个。
谢谢
您看到的 ValueError
是因为您正在尝试检查 if(some_series)
。我不确定哪一行给出了您指出的错误,但看起来您的任何 if 语句都可能导致此问题。
例如,第一个 if 语句将一系列值与单个值进行比较。结果是一系列布尔值,而不是 if 语句可以理解的单个 True/False。 pd.isnull
.
也可能发生同样的情况
您应该检查您的哪些命令给出了数组结果,并考虑它如何符合您的代码逻辑。
如果我正确理解你的问题,这里有一个可能的解决方案:
def yearfilt(group):
# Apply .max() twice to get a single value across the group.
# Otherwise the results is a Series, and using if will result in a ValueError.
if group[['Avail', 'Change']].max().max() < 2018:
# Returns true if there is a unique status value.
if group['Status'].unique().shape[0] == 1:
# Return last row as a dataframe.
return group.iloc[-1:]
else:
# Return ALL rows with status not null (may be more than 1?).
return group[group['Status'] != 'null']
else:
if group['Status'].unique().shape[0] == 1:
# Return first row as a dataframe.
return group.iloc[:1]
else:
return group[group['Status'] != 'null']
dataset.groupby('ID').apply(yearfilt).reset_index(drop=True)
要记住几件事:
- 传递给您在
groupby().apply
中使用的函数的每个参数都传递给整个数据帧的一个子集。您需要 return 新对象,而不是修改您的函数接收的组。
- 如果您使用
isnull
,您尝试过滤的值必须是 None
,而不是字符串 'null'
、'None'
、'nan'
等。参见 the docs 缺失值。
- 您不能在
Series
上使用 if
语句,只能使用一个值。
如果年份高于或低于某个范围,我想对我的数据框应用不同的过滤器。这是数据框
dataset=pd.DataFrame({'ID': [1,1,1,2,2,2,3,3,3,4,4,4,5,5,5],
'Avail' : [2017,2017,2017,2018,2018,2018,2017,2017,2017,2017,2017,2017,2017,2018,2018],
'Change' : [0,0,2018,0,0,0,0,0,0,0,0,0,2018,0,0],
'Pref' : [1,2,3,1,2,3,1,2,3,1,2,3,1,2,3],
'Status': ['null', 'null','Q','null','null','null','Q','null','null','null','null','null','Q','null','null']
},columns=['ID', 'Avail', 'Change', 'Pref', 'Status'])
这是我编写的产生错误的代码:
def yearfilt(x):
if x.loc[:, ['Avail', 'Change']].values.max(axis=1) < 2018:
if pd.isnull(x.Status):
x.drop_duplicates(subset=['STU_ID','Status' ], keep='last')
else:
x=x.drop(x[pd.isnull(x.Status)].index)
else:
if pd.isnull(x.ASSESSMENT_OUTCOME_CD):
x.drop_duplicates(subset=['STU_ID','Status' ], keep='first')
else:
x=x.drop(x[pd.isnull(x.Status)].index)
df=dataset.groupby(['ID']).apply(yearfilt).sort_values(["ID"]).reset_index(drop=True)
错误是
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
我想执行的是:
If the max (Avail, Change) < 2018 then
Case 1: the same status --> drop duplicates and keep the last
Case 2: different status --> drop null-value statuses
else (in other words max (Avail, Change) = 2018)
Case 1: the same status --> drop duplicates and keep the first
Case 2: different status --> drop null-value statuses
输出应如下所示:
ID Year Change Pref Status
1 2017 2018 3 Q
2 2018 0 1 null
3 2017 0 1 Q
4 2017 0 3 null
5 2017 2018 1 Q
基本上,每个 ID 我只想保留一个。 谢谢
您看到的 ValueError
是因为您正在尝试检查 if(some_series)
。我不确定哪一行给出了您指出的错误,但看起来您的任何 if 语句都可能导致此问题。
例如,第一个 if 语句将一系列值与单个值进行比较。结果是一系列布尔值,而不是 if 语句可以理解的单个 True/False。 pd.isnull
.
您应该检查您的哪些命令给出了数组结果,并考虑它如何符合您的代码逻辑。
如果我正确理解你的问题,这里有一个可能的解决方案:
def yearfilt(group):
# Apply .max() twice to get a single value across the group.
# Otherwise the results is a Series, and using if will result in a ValueError.
if group[['Avail', 'Change']].max().max() < 2018:
# Returns true if there is a unique status value.
if group['Status'].unique().shape[0] == 1:
# Return last row as a dataframe.
return group.iloc[-1:]
else:
# Return ALL rows with status not null (may be more than 1?).
return group[group['Status'] != 'null']
else:
if group['Status'].unique().shape[0] == 1:
# Return first row as a dataframe.
return group.iloc[:1]
else:
return group[group['Status'] != 'null']
dataset.groupby('ID').apply(yearfilt).reset_index(drop=True)
要记住几件事:
- 传递给您在
groupby().apply
中使用的函数的每个参数都传递给整个数据帧的一个子集。您需要 return 新对象,而不是修改您的函数接收的组。 - 如果您使用
isnull
,您尝试过滤的值必须是None
,而不是字符串'null'
、'None'
、'nan'
等。参见 the docs 缺失值。 - 您不能在
Series
上使用if
语句,只能使用一个值。