我有一个pandas数据框,如:
df = pd.read_csv('fruit.csv')
print(df)
fruitname quant
0 apple 10
1 apple 11
2 apple 13
3 banana 10
4 banana 20
5 banana 30
6 banana 40
7 pear 10
8 pear 102
9 pear 1033
10 pear 1012
11 pear 101
12 pear 100
13 pear 1044
14 orange 10
我想删除最后一个条目PER FRUIT,如果该水果有奇数(不均匀)条目数(%2 == 1)。没有循环数据帧。因此,上述结果将是:
- 删除最后一个苹果,因为苹果发生了3次 - 删除最后一颗梨 - 删除最后一个(仅)橙色
导致:
fruitname quant
0 apple 10
1 apple 11
2 banana 10
3 banana 20
4 banana 30
5 banana 40
6 pear 10
7 pear 102
8 pear 1033
9 pear 1012
10 pear 101
11 pear 100
这可能吗?或者我必须循环DF?我一直在谷歌搜索4天,只是无法弄清楚如何做到这一点。
答案 0 :(得分:6)
使用value_counts
确定每个水果的项目数,并根据是否有奇数来构建它们的列表。
我们可以通过使用%
模运算符生成1
或0
来实现此目的,使用astype
进行转换以创建布尔掩码。
使用布尔掩码来屏蔽value_counts
的索引。
现在你有一个水果列表,通过过滤df迭代每个水果,并使用iloc[-1]
和.name
属性获取最后一个索引标签,并将其附加到列表中。
现在drop
列表中的这些标签:
In [393]:
fruits = df['fruitname'].value_counts().index[(df['fruitname'].value_counts() % 2).astype(bool)]
idx = []
for fruit in fruits:
idx.append(df[df['fruitname']==fruit].iloc[-1].name)
df.drop(idx)
Out[393]:
fruitname quant
0 apple 10
1 apple 11
3 banana 10
4 banana 20
5 banana 30
6 banana 40
7 pear 10
8 pear 102
9 pear 1033
10 pear 1012
11 pear 101
12 pear 100
突破以上:
In [394]:
df['fruitname'].value_counts()
Out[394]:
pear 7
banana 4
apple 3
orange 1
Name: fruitname, dtype: int64
In [398]:
df['fruitname'].value_counts() % 2
Out[398]:
pear 1
banana 0
apple 1
orange 1
Name: fruitname, dtype: int64
In [399]:
fruits = df['fruitname'].value_counts().index[(df['fruitname'].value_counts() % 2).astype(bool)]
fruits
Out[399]:
Index(['pear', 'apple', 'orange'], dtype='object')
In [401]:
for fruit in fruits:
print(df[df['fruitname']==fruit].iloc[-1].name)
13
2
14
实际上,您可以使用last_valid_index
代替iloc[-1].name
,以便以下方法有效:
fruits = df['fruitname'].value_counts().index[(df['fruitname'].value_counts() % 2).astype(bool)]
idx = []
for fruit in fruits:
idx.append(df[df['fruitname']==fruit].last_valid_index())
df.drop(idx)
答案 1 :(得分:5)
EdChum的替代方法,使用groupby
:
>>> grouped = df.groupby("fruitname")["fruitname"]
>>> lengths = grouped.transform(len)
>>> df.loc[~((lengths % 2 == 1) & (grouped.cumcount() == lengths-1))]
fruitname quant
0 apple 10
1 apple 11
3 banana 10
4 banana 20
5 banana 30
6 banana 40
7 pear 10
8 pear 102
9 pear 1033
10 pear 1012
11 pear 101
12 pear 100
这可以通过使用transform
(和cumcount
,其行为类似于一种变换,因为它广播到原始索引)来为我们提供一个帧长系列,我们可以使用它:
>>> lengths
0 3
1 3
2 3
3 4
4 4
5 4
6 4
7 7
8 7
9 7
10 7
11 7
12 7
13 7
14 1
Name: fruitname, dtype: object
>>> grouped.cumcount()
0 0
1 1
2 2
3 0
4 1
5 2
6 3
7 0
8 1
9 2
10 3
11 4
12 5
13 6
14 0
dtype: int64
答案 2 :(得分:1)
您可以使用apply函数:
def remove_last_odd_row(fr):
nrow = fr.shape[0]
if nrow % 2 > 0:
return fr[:(nrow - 1)]
else:
return fr
fr = fr.groupby("fruitname").apply(remove_last_odd_row).reset_index(drop=True)
答案 3 :(得分:0)
我对熊猫不是很熟悉,但这是一个答案。
for fruit in pd.unique(df.fruitname):
df1=df[df.fruitname==fruit]
if len(df1)%2 == 1:
df=df.drop(df1.last_valid_index())