如何根据已从一个类别转移到另一个类别(按顺序)的 id 列计算行数?
How to count the numbers of rows based on an id column that have shifted from one category to another (in order)?
我有一个这样的 pandas 数据框:
id year_group category
0 8300 1 low
1 8300 2 medium
2 11725 1 low
3 11725 2 low
4 18068 1 medium
... ... ... ...
59354 18962 1 low
59355 11669 1 low
59356 13110 3 low
59357 2378 1 low
59358 19363 1 low
[59359 rows x 3 columns]
我正在尝试根据一年(year_group 列)确定有多少 ID 从一个类别转移到另一个类别。例如,对于 id 8300,从第 1 年到第 2 年的转变表明类别从低到中(按此顺序)的变化。我想计算每个类别在 year_group 秒 1 到 3 之间发生这种情况的次数。
我不确定如何完成此操作。目前,我考虑过在尝试对所有内容进行分组之前删除每个 year_group 并制作单独的数据框,如下所示:
# year 1 and 2
years_1_2 = df.drop(df[df.year_group == 3].index)
但是,我不知道如何确保分组是基于 year_group 的位置,即第 1 年到第 2 年而不是第 2 年到第 1 年。
也许我可以做一些更精简的事情。也许利用 np.where... 关于如何最好地解决这个问题有什么建议吗?
也许这可以帮助您入门。我相信这有点冗长,但很清楚。
在线评论
# added and modified data for just 2 years
data=''' id year_group category
0 8300 1 low
1 8300 2 medium
2 11725 1 low
3 11725 2 low
4 18068 1 medium
5 18068 2 low
6 18962 1 low
7 18962 2 low
8 21 1 low
9 21 2 medium'''
df = pd.read_csv(io.StringIO(data), sep=' \s+', engine='python')
# sort to keep ids and year_groups ascending
df.sort_values(['id', 'year_group'], ascending=[True, True], inplace=True)
id year_group category
8 21 1 low
9 21 2 medium
0 8300 1 low
1 8300 2 medium
2 11725 1 low
3 11725 2 low
4 18068 1 medium
5 18068 2 low
6 18962 1 low
7 18962 2 low
# if you have year 3, this will only take years 1 and 2
# if a grouping has a count of 2, that means there is no change from one year to the next, so drop everything that didn't change
dft = df[df[df['year_group'] != 3].groupby(['id', 'category'])['year_group'].transform('count') < 2]
id year_group category
8 21 1 low
9 21 2 medium
0 8300 1 low
1 8300 2 medium
4 18068 1 medium
5 18068 2 low
# making lists that show movement from low - medium, medium - low, etc...
yearlychanges = dft.groupby('id')['category'].apply(list).reset_index()
id category
0 21 [low, medium]
1 8300 [low, medium]
2 18068 [medium, low]
# convert lists to strings for counting
yearlychanges['changes'] = yearlychanges.apply(lambda x: '-'.join(x['category']), axis=1)
id category changes
0 21 [low, medium] low-medium
1 8300 [low, medium] low-medium
2 18068 [medium, low] medium-low
# count number of changes
yearlychanges[['changes', 'id']].groupby('changes').count()
id
changes
low-medium 2
medium-low 1
如果我理解正确的话:
Setup
df = pd.DataFrame(data={{'id': [8300, 8300, 8300, 8301, 8301, 8301], 'year_group': [1, 2, 3, 1, 2, 3], 'category': ['low', 'medium', 'low', 'low', 'medium', 'low']}})
Code
df['shift'] = df.groupby('id')['category'].apply(lambda x: x + ' ' + x.shift(-1))
shifts = df.dropna(subset=['shift']).groupby(['shift']).size()
Input
id year_group category
0 8300 1 low
1 8300 2 medium
2 8300 3 low
59355 8301 1 low
59356 8301 2 medium
59357 8301 3 low
Output
:
shift
low medium 2
medium low 2
我有一个这样的 pandas 数据框:
id year_group category
0 8300 1 low
1 8300 2 medium
2 11725 1 low
3 11725 2 low
4 18068 1 medium
... ... ... ...
59354 18962 1 low
59355 11669 1 low
59356 13110 3 low
59357 2378 1 low
59358 19363 1 low
[59359 rows x 3 columns]
我正在尝试根据一年(year_group 列)确定有多少 ID 从一个类别转移到另一个类别。例如,对于 id 8300,从第 1 年到第 2 年的转变表明类别从低到中(按此顺序)的变化。我想计算每个类别在 year_group 秒 1 到 3 之间发生这种情况的次数。
我不确定如何完成此操作。目前,我考虑过在尝试对所有内容进行分组之前删除每个 year_group 并制作单独的数据框,如下所示:
# year 1 and 2
years_1_2 = df.drop(df[df.year_group == 3].index)
但是,我不知道如何确保分组是基于 year_group 的位置,即第 1 年到第 2 年而不是第 2 年到第 1 年。
也许我可以做一些更精简的事情。也许利用 np.where... 关于如何最好地解决这个问题有什么建议吗?
也许这可以帮助您入门。我相信这有点冗长,但很清楚。 在线评论
# added and modified data for just 2 years
data=''' id year_group category
0 8300 1 low
1 8300 2 medium
2 11725 1 low
3 11725 2 low
4 18068 1 medium
5 18068 2 low
6 18962 1 low
7 18962 2 low
8 21 1 low
9 21 2 medium'''
df = pd.read_csv(io.StringIO(data), sep=' \s+', engine='python')
# sort to keep ids and year_groups ascending
df.sort_values(['id', 'year_group'], ascending=[True, True], inplace=True)
id year_group category
8 21 1 low
9 21 2 medium
0 8300 1 low
1 8300 2 medium
2 11725 1 low
3 11725 2 low
4 18068 1 medium
5 18068 2 low
6 18962 1 low
7 18962 2 low
# if you have year 3, this will only take years 1 and 2
# if a grouping has a count of 2, that means there is no change from one year to the next, so drop everything that didn't change
dft = df[df[df['year_group'] != 3].groupby(['id', 'category'])['year_group'].transform('count') < 2]
id year_group category
8 21 1 low
9 21 2 medium
0 8300 1 low
1 8300 2 medium
4 18068 1 medium
5 18068 2 low
# making lists that show movement from low - medium, medium - low, etc...
yearlychanges = dft.groupby('id')['category'].apply(list).reset_index()
id category
0 21 [low, medium]
1 8300 [low, medium]
2 18068 [medium, low]
# convert lists to strings for counting
yearlychanges['changes'] = yearlychanges.apply(lambda x: '-'.join(x['category']), axis=1)
id category changes
0 21 [low, medium] low-medium
1 8300 [low, medium] low-medium
2 18068 [medium, low] medium-low
# count number of changes
yearlychanges[['changes', 'id']].groupby('changes').count()
id
changes
low-medium 2
medium-low 1
如果我理解正确的话:
Setup
df = pd.DataFrame(data={{'id': [8300, 8300, 8300, 8301, 8301, 8301], 'year_group': [1, 2, 3, 1, 2, 3], 'category': ['low', 'medium', 'low', 'low', 'medium', 'low']}})
Code
df['shift'] = df.groupby('id')['category'].apply(lambda x: x + ' ' + x.shift(-1))
shifts = df.dropna(subset=['shift']).groupby(['shift']).size()
Input
id year_group category
0 8300 1 low
1 8300 2 medium
2 8300 3 low
59355 8301 1 low
59356 8301 2 medium
59357 8301 3 low
Output
:
shift
low medium 2
medium low 2