在pandas数据框中,我有一个如下所示的列:
0 M
1 E
2 L
3 M.1
4 M.2
5 M.3
6 E.1
7 E.2
8 E.3
9 E.4
10 L.1
11 L.2
12 M.1.a
13 M.1.b
14 M.1.c
15 M.2.a
16 M.3.a
17 E.1.a
18 E.1.b
19 E.1.c
20 E.2.a
21 E.3.a
22 E.3.b
23 E.4.a
我需要对第一个元素为E, M, or L
的所有值进行分组,然后,对于每个组,我需要创建一个子组,其中索引为1, 2, or 3
,其中包含每个{的一个记录{ {1}}(a,b,c,...)
解决方案可能适用于任意数量级别的连接元素(在这种情况下,级别数为3(例如:A.1.a))
lowercase letter
我尝试过:
0 1 2
E 1 a
b
c
2 a
3 a
b
4 a
L 1
2
M 1 a
b
c
2 a
3 a
但结果是缺少 L级,因为它在最后一个子级别没有记录
解决方法是添加一个虚拟变量,然后将其删除......如:
df.groupby([0,1,2]).count()
给出:
df[2][(df[0]=='L') & (df[2].isnull()) & (df[1].notnull())]='x'
df = df.replace(np.nan,' ', regex=True)
df.sort_values(0, ascending=False, inplace=True)
newdf = df.groupby([0,1,2]).count()
然后我在代码中处理0 1 2
E 1 a
b
c
2 a
3 a
b
4 a
L 1 x
2 x
M 1 a
b
c
2 a
3 a
条目dummy
...
如何避免这种使用x
的方式?
答案 0 :(得分:1)
假设正在考虑的列由s
表示,我们可以:
在"."
分隔符上与expand=True
分开,以生成展开的DF
。
fnc
:检查分组帧的所有元素是否仅由None
组成,然后用虚拟条目""
替换它们,该条目通过建立列表理解。稍后在筛选列表上调用一系列构造函数。随后使用None
删除此处的任何dropna
。
执行groupby
w.r.t. 0 & 1 列名并将fnc
应用于 2 。
split_str = s.str.split(".", expand=True)
fnc = lambda g: pd.Series(["" if all(x is None for x in g) else x for x in g]).dropna()
split_str.groupby([0, 1])[2].apply(fnc)
产生
0 1
E 1 1 a
2 b
3 c
2 1 a
3 1 a
2 b
4 1 a
L 1 0
2 0
M 1 1 a
2 b
3 c
2 1 a
3 1 a
Name: 2, dtype: object
要获得展平的DF
,请重置与之前用于对DF
进行分组的级别相同的索引:
split_str.groupby([0, 1])[2].apply(fnc).reset_index(level=[0, 1]).reset_index(drop=True)
产生
0 1 2
0 E 1 a
1 E 1 b
2 E 1 c
3 E 2 a
4 E 3 a
5 E 3 b
6 E 4 a
7 L 1
8 L 2
9 M 1 a
10 M 1 b
11 M 1 c
12 M 2 a
13 M 3 a
答案 1 :(得分:0)
也许你必须找到一种使用正则表达式的方法。
import pandas as pd
df = pd.read_clipboard(header=None).iloc[:, 1]
df2 = df.str.extract(r'([A-Z])\.?([0-9]?)\.?([a-z]?)')
print df2.set_index([0,1])
结果是,
2
0 1
M
E
L
M 1
2
3
E 1
2
3
4
L 1
2
M 1 a
1 b
1 c
2 a
3 a
E 1 a
1 b
1 c
2 a
3 a
3 b
4 a