use*_*381 5 python apply pandas
我有一个像这样的pandas DataFrame:
From To Val
GE VD 1000
GE VS 1600
VS VD 1500
VS GE 600
VD GE 1200
VD VS 1300
Run Code Online (Sandbox Code Playgroud)
我想将"from"或"to"列中没有"GE"的每一行替换为两行,一行在"from"列中有"GE",另一行在"to"中有"GE". "专栏.在上面的示例中,我将通过以下两行替换第三行:
GE VD 1500
VS GE 1500
我尝试使用"apply"但我无法弄清楚如何返回正确的数据框.例如
def myfun(row):
if "GE" not in (row["from"], row["to"]):
row1=pd.DataFrame(row).T
row2=row1.copy()
row1["from"]="GE"
row2["to"]="GE"
return pd.concat([row1, row2])
else:
return pd.DataFrame(row).T
Run Code Online (Sandbox Code Playgroud)
给出一个奇怪的结果:
>> df.apply(myfun, axis=1)
Val from to
0 Val from to
1 Val from to
2 Val from to
3 Val from to
4 Val from to
5 Val from to
Run Code Online (Sandbox Code Playgroud)
虽然我的功能看似正确:
>> myfun(df.loc[5])
Val from to
5 13 GE VD
5 13 VS GE
Run Code Online (Sandbox Code Playgroud)
通过在两个子数据帧中过滤我的数据帧,我可以想到一种方法,一个行需要重复,另一个需要重复.然后复制第一个数据帧,进行更改并将所有三个DF整理在一起.但它很难看.有谁能建议更优雅的方式?
换句话说,应用函数可以返回一个DataFrame,就像在R中我们会用ddply做的那样吗?
谢谢
过滤:
In [153]: sub = df[(~df[['From', 'To']].isin(['GE'])).all(1)]
In [154]: sub
Out[154]:
From To Val
2 VS VD 1500
5 VD VS 1300
[2 rows x 3 columns]
In [179]: good = df.ix[df.index - sub.index]
In [180]: good
Out[180]:
From To Val
0 GE VD 1000
1 GE VS 1600
3 VS GE 600
4 VD GE 1200
[4 rows x 3 columns]
Run Code Online (Sandbox Code Playgroud)
定义一个函数,将所需的值作为DataFrame提供:
def new_df(row):
return pd.DataFrame({"From": ["GE", row["From"]],
"To": [row["To"], "GE"],
"Val": [row["Val"], row["Val"]]})
Run Code Online (Sandbox Code Playgroud)
将该函数应用于行:
In [181]: new = pd.concat([new_df(y) for _, y in x.iterrows()], axis=0, ignore_index=True)
In [182]: new
Out[182]:
From To Val
0 GE VD 1500
1 VS GE 1500
2 GE VS 1300
3 VD GE 1300
[4 rows x 3 columns]
Run Code Online (Sandbox Code Playgroud)
并且连在一起
In [183]: pd.concat([good, new], axis=0, ignore_index=True)
Out[183]:
From To Val
0 GE VD 1000
1 GE VS 1600
2 VS GE 600
3 VD GE 1200
4 GE VD 1500
5 VS GE 1500
6 GE VS 1300
7 VD GE 1300
[8 rows x 3 columns]
Run Code Online (Sandbox Code Playgroud)
这使用了两次通过。else
如果您添加一个条件来连接将保持不变的行,则可以缩短它。然而,我发现这更具可读性,并且由于我们用来itertuples
遍历行,所以这里的成本是线性的,我们只是根据需要形成每个元组(而不是同时为所有行生成一个大的元组列表)。
同样,您可以在语句中弹出一行if
,并将其位置上的两个新行连接回原始数据对象df
,这样就不会产生创建的内存成本keeper_rows
。除非数据帧非常巨大,否则通常不值得对这样的任务进行此类优化。
keeper_rows = df.ix[[i for i,x in enumerate(df.itertuples()) if 'GE' in x[0:2]]]
for row_as_tuple in df.itertuples():
from_other, to_other, val = row_as_tuple
if "GE" not in (from_other, to_other):
new_rows = {"From":["GE", from_other],
"To" :[to_other, "GE"],
"Val" :[val, val]}
keeper_rows = pandas.concat([keeper_rows, pandas.DataFrame(new_rows)],
ignore_index=True)
Run Code Online (Sandbox Code Playgroud)