I have a dataframe like:
principalDf =
| x || y || z || values |
| x0 || y0 || z0 || areal |
| x1 || y1 || z1 || aimag |
| x2 || y2 || z2 || breal |
| x3 || y3 || z3 || bimag |
I want to produce:
frobprincipalDf =
| x || y || z || values |
|sqrt(x0^2 x1^2)||sqrt(y0^2 y1^2)||sqrt(z0^2 z1^2)|| a |
|sqrt(x2^2 x3^2)||sqrt(y2^2 y3^2)||sqrt(z2^2 z3^2)|| b |
I'm generating the required x, y and z data by:
frobprincipalDf = pd.DataFrame(columns=principalDf.columns)
for col in principalDf.columns[:-1]:
for index in range(0,len(principalDf),2):
frobnorm = np.sqrt(principalDf[col].iloc[index]**2 principalDf[col].iloc[index 1]**2)
print(frobnorm)
How can I add frobnorm to a specific col
in the newly created frobprincipalDf
?
Is there a better way to do this than nested for loops?
It should be generalisable for any value name, such that if another value begins with a, it will not 'group' them together.
It looks as though the below is a complete solution to the initial problem of even-index pairs of rows addition. This is slightly modified answer of quasi-human's answer. The secondary problem of adding a single value to a specific df
column is still there though.
frobprincipalDf = np.sqrt(principalDf[['x', 'y', 'z']].shift() ** 2 principalDf[['x', 'y', 'z']] ** 2)
frobprincipalDf = pd.concat([frobprincipalDf,principalDf['values'].str[:2]], axis=1)
frobprincipalDf = frobprincipalDf[frobprincipalDf.index % 2 == 1].reset_index(drop=True)
CodePudding user response:
You can use shift
method to pick out a pair of rows.
Code:
import numpy as np
import pandas as pd
# Create a sample dataframe
import io
s='''x,y,z,values
1,5,9,areal
2,6,10,aimag
3,7,11,breal
4,8,12,bimag'''
df = pd.read_csv(io.StringIO(s))
# Calculate values
df_calc = np.sqrt(df[['x', 'y', 'z']].shift() ** 2 df[['x', 'y', 'z']] ** 2)
# Deal with strings
df_str = df['values'].str[:1]
# Concatenate the two dataframes
df_result = pd.concat([df_calc, df_str], axis=1)
# Pick out odd indice
df_result = df_result[df_result.index % 2 == 1].reset_index(drop=True)
Input:
x | y | z | values |
---|---|---|---|
1 | 5 | 9 | areal |
2 | 6 | 10 | aimag |
3 | 7 | 11 | breal |
4 | 8 | 12 | bimag |
Output:
x | y | z | values |
---|---|---|---|
2.23607 | 7.81025 | 13.4536 | a |
5 | 10.6301 | 16.2788 | b |
CodePudding user response:
You could use groupby
agg
:
import numpy as np
group = df['values'].str.extract('(.*)(?:real|imag)', expand=False)
# 0 a
# 1 a
# 2 b
# 3 b
(df.select_dtypes('number')
.groupby(group)
.agg(lambda x: np.sqrt((x**2).sum()))
.reset_index()
)
example input:
x y z values
0 1 2 3 areal
1 4 5 6 aimag
2 7 8 9 breal
3 10 11 12 bimag
output:
values x y z
0 a 4.123106 5.385165 6.708204
1 b 12.206556 13.601471 15.000000