how to multiply multiple columns by a column in Pandas - python

I would like to have:
df[['income_1', 'income_2']] * df['mtaz_proportion']
return those columns multiplied by df['mtaz_proportion']
so that I can set
df[['mtaz_income_1', 'mtaz_income_2']] =
df[['income_1', 'income_2']] * df['mtaz_proportion']
but instead I get:
income_1 income_2 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
0 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ...
1 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ...
2 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ...
ect...
what simple thing am I missing?
Thank you!

use multiply method and set axis="index":
df[["A", "B"]].multiply(df["C"], axis="index")

Another way of writing the answer of HYRY:
df.loc[:,['A', 'B']] = df.loc[:,['A', 'B']].multiply(df.loc[:, 'C'], axis="index")

Convert both factors to numpy arrays using to_numpy:
df.loc[:, ['D', 'E']] = df[['A', 'B']].to_numpy() * df[['C']].to_numpy()

Related

Is there a way for inserting/adding NaN rows and columns on a DataFrame?

I want to turn a DataFrame (or a numpy array):
df1:
0 1 2
0 1. 5. 9.
1 2. 6. 10.
2 3. 7. 11.
3 4. 8. 12.
into a DataFrame like this:
df1
0 1 2 3 4 5 6
0 NaN NaN NaN NaN NaN NaN NaN
1 NaN 1. NaN 5. NaN 9. NaN
2 NaN NaN NaN NaN NaN NaN NaN
3 NaN 2. NaN 6. NaN 10. NaN
4 NaN NaN NaN NaN NaN NaN NaN
5 NaN 3. NaN 7. NaN 11. NaN
6 NaN NaN NaN NaN NaN NaN NaN
7 NaN 4. NaN 8. NaN 12. NaN
8 NaN NaN NaN NaN NaN NaN NaN
, i.e., I want to insert NaN rows and columns on df1 (as many as I want)
Could you make this work even for a large DataFrame, where you cannot do this manually?
So far, I have this:
import numpy as np
import pandas as pd
p = np.arange(1,13).reshape(4,3)
p1 = pd.DataFrame(p)
#Add a row of NaN's on p1
p1.index = range(1, 2*len(p1)+1, 2)
p1 = p1.reindex(index=range(2*len(p1)))
#Repeat for rows...I know its a lil bit st*pid
p1 = pd.DataFrame(p1)
p1.index = range(1, 2*len(p1)+1, 2)
p1 = p1.reindex(index=range(2*len(p1)))
#etc...
p1 = pd.DataFrame(p1)
p1.index = range(1, 2*len(p1)+1, 2)
p1 = p1.reindex(index=range(2*len(p1)))
It seems to work, but only for rows until now...
e.g., see this
Based on this answer you can interleave two dataframes on a particular axis.
pd.concat([df1, df2]).sort_index().reset_index(drop=True)
You can start by interleaving by rows (axis=0) df1 with a dataframe containing nan values. And do the same on the columns (axis=1) with another dataframe of nan values.
df1 = pd.DataFrame([[1., 5., 9.], [2., 6., 10.], [3., 7., 11.], [4., 8., 12.]])
rows, cols = df1.shape
Tricky part is getting the sizes right:
nan1 = pd.DataFrame([[np.nan]*cols]*(rows+1))
nan2 = pd.DataFrame([[np.nan]*(cols + 1)]*(2*rows + 1))
Then perform two consecutives concatenations, on axis=0 (default one) and axis=1:
df2_r = pd.concat([nan1, df1]).sort_index().reset_index(drop=True)
df2 = pd.concat([nan2, df2_r], axis=1).sort_index(axis=1).T.reset_index(drop=True).T
Edit: it seems there's is no built-in method to reset the columns indexing. However this will do:
df.T.reset_index(drop=True).T
Here are the results for each operation:
df1
0 1 2
0 1.0 5.0 9.0
1 2.0 6.0 10.0
2 3.0 7.0 11.0
3 4.0 8.0 12.0
nan1
0 1 2
0 NaN NaN NaN
1 NaN NaN NaN
2 NaN NaN NaN
3 NaN NaN NaN
4 NaN NaN NaN
concat on axis=0
0 1 2
0 NaN NaN NaN
1 1.0 5.0 9.0
2 NaN NaN NaN
3 2.0 6.0 10.0
4 NaN NaN NaN
5 3.0 7.0 11.0
6 NaN NaN NaN
7 4.0 8.0 12.0
8 NaN NaN NaN
nan2
0 1 2 3
0 NaN NaN NaN NaN
1 NaN NaN NaN NaN
2 NaN NaN NaN NaN
3 NaN NaN NaN NaN
4 NaN NaN NaN NaN
5 NaN NaN NaN NaN
6 NaN NaN NaN NaN
7 NaN NaN NaN NaN
8 NaN NaN NaN NaN
concat on axis=1
0 1 2 3 4 5 6
0 NaN NaN NaN NaN NaN NaN NaN
1 NaN 1.0 NaN 5.0 NaN 9.0 NaN
2 NaN NaN NaN NaN NaN NaN NaN
3 NaN 2.0 NaN 6.0 NaN 10.0 NaN
4 NaN NaN NaN NaN NaN NaN NaN
5 NaN 3.0 NaN 7.0 NaN 11.0 NaN
6 NaN NaN NaN NaN NaN NaN NaN
7 NaN 4.0 NaN 8.0 NaN 12.0 NaN
8 NaN NaN NaN NaN NaN NaN NaN
I am curious to see what you have tried so far, but here is an easy "quick and dirty" way to do it for your example. This is not a definitive answer: I'll let you figure out how to generalize it to any dataframe sizes/content you might have.
I am providing this code for your example so you have an idea which pandas functions/properties to use.
import pandas as pd
import numpy as np
# Making your base DataFrame
df = pd.DataFrame([[1,5,9], [2,6,8], [3,7,4]])
df:
0 1 2
0 1 5 9
1 2 6 8
2 3 7 4
spacing out your columns existing columns numbers and adding filling the left columns numbers with NaN:
df.columns = [1,3,5]
for i in range(0, 8, 2):
df[i] = np.NaN
df:
1 3 5 0 2 4 6
0 1 5 9 NaN NaN NaN NaN
1 2 6 8 NaN NaN NaN NaN
2 3 7 4 NaN NaN NaN NaN
Now adding extra rows, with NaN data (we need 4 more with 7 columns)
df2 = pd.DataFrame([[np.NaN] * 7] * 4)
df = pd.concat([df, df2])
df3:
0 1 2 3 4 5 6
0 NaN 1.0 NaN 5.0 NaN 9.0 NaN
1 NaN 2.0 NaN 6.0 NaN 8.0 NaN
2 NaN 3.0 NaN 7.0 NaN 4.0 NaN
0 NaN NaN NaN NaN NaN NaN NaN
1 NaN NaN NaN NaN NaN NaN NaN
2 NaN NaN NaN NaN NaN NaN NaN
3 NaN NaN NaN NaN NaN NaN NaN
As you can see: we have the right data, and it is now only a matter of ordering your rows.
df3.index = [1,3,5,0,2,4,6]
df3 = df3.sort_index()
df3:
0 1 2 3 4 5 6
0 NaN NaN NaN NaN NaN NaN NaN
1 NaN 1.0 NaN 5.0 NaN 9.0 NaN
2 NaN NaN NaN NaN NaN NaN NaN
3 NaN 2.0 NaN 6.0 NaN 8.0 NaN
4 NaN NaN NaN NaN NaN NaN NaN
5 NaN 3.0 NaN 7.0 NaN 4.0 NaN
6 NaN NaN NaN NaN NaN NaN NaN
I think this is a very elegant way to solve this.
array=np.array([[1,5,9],[2,6,10],[3,7,11],[4,8,12]])
Data=pd.DataFrame(array)
Data.index=Data.index*2+1
Data.columns=Data.columns*2+1
Data=Data.reindex(list(range(0,9)))
Data=Data.T.reindex(list(range(0,9)))
A fast way using numpy (work with dataframe as well):
# Sample data
a = np.arange(1,13).reshape(4,3)
df = pd.DataFrame(a)
# New data with empty values
a2 = np.empty([i*2+1 for i in a.shape])
a2[:] = np.nan
a2[1::2, 1::2] = a
Output of pd.DataFrame(a2):
0 1 2 3 4 5 6
0 NaN NaN NaN NaN NaN NaN NaN
1 NaN 1.0 NaN 2.0 NaN 3.0 NaN
2 NaN NaN NaN NaN NaN NaN NaN
3 NaN 4.0 NaN 5.0 NaN 6.0 NaN
4 NaN NaN NaN NaN NaN NaN NaN
5 NaN 7.0 NaN 8.0 NaN 9.0 NaN
6 NaN NaN NaN NaN NaN NaN NaN
7 NaN 10.0 NaN 11.0 NaN 12.0 NaN
8 NaN NaN NaN NaN NaN NaN NaN
Note: If you have a DataFrame, just replace a.shape by df.shape, and a by df.values.

Replace dataframe values by NaN

I am working with a pandas dataframe of 15 rows and 8 columns, such a:
A B ... G H
0 0.158979 0.187282 ... 0.330566 0.458748
1 0.227254 0.273307 ... 0.489372 0.649698
2 0.308775 0.351285 ... 0.621399 0.833404
3 0.375850 0.444228 ... 0.759206 0.929980
4 0.431860 0.507906 ... 0.850741 1.038544
5 0.507219 0.596291 ... 0.980404 1.145819
6 0.570170 0.676551 ... 1.094201 1.282077
7 0.635122 0.750434 ... 1.155645 1.292930
8 0.704220 0.824748 ... 1.261516 1.395316
9 0.762619 0.887669 ... 1.337860 1.410864
10 0.824553 0.968889 ... 1.407665 1.437886
11 0.893413 1.045289 ... 1.519902 1.514017
12 0.946757 1.109964 ... 1.561611 1.478634
13 1.008294 1.174139 ... 1.596135 1.501220
14 1.053086 1.227203 ... 1.624630 1.503892
where columns from C to F have been omitted.
I would like to know how I can find the closest value to 1 for every column. Once this value is found I would like to replace the rest of the values in the columns by NaN, with the exception of the values corresponding to the previous and next row. Then obtaining a dataframe like that:
A B ... G H
0 NaN NaN ... NaN NaN
1 NaN NaN ... NaN NaN
2 NaN NaN ... NaN NaN
3 NaN NaN ... NaN 0.929980
4 NaN NaN ... 0.850741 1.038544
5 NaN NaN ... 0.980404 1.145819
6 NaN NaN ... 1.094201 NaN
7 NaN NaN ... NaN NaN
8 NaN NaN ... NaN NaN
9 NaN 0.887669 ... NaN NaN
10 NaN 0.968889 ... NaN NaN
11 NaN 1.045289 ... NaN NaN
12 0.946757 NaN ... NaN NaN
13 1.008294 NaN ... NaN NaN
14 1.053086 NaN ... NaN NaN
Does anyone has a sugestion for this?
Thanks in advance
you can use the fact that the closest to 1 is actually the min of the abs of df once remove 1. So check where the min is meet, use shift once with 1 and once with -1 to get the next and previous row. use this mask in where.
df_ = (df-1).abs()
df_ = df_.min() == df_
df_ = df_|df_.shift(1)|df_.shift(-1)
df_ = df.where(df_)
print(df_)
A B G H
0 NaN NaN NaN NaN
1 NaN NaN NaN NaN
2 NaN NaN NaN NaN
3 NaN NaN NaN 0.929980
4 NaN NaN 0.850741 1.038544
5 NaN NaN 0.980404 1.145819
6 NaN NaN 1.094201 NaN
7 NaN NaN NaN NaN
8 NaN NaN NaN NaN
9 NaN 0.887669 NaN NaN
10 NaN 0.968889 NaN NaN
11 NaN 1.045289 NaN NaN
12 0.946757 NaN NaN NaN
13 1.008294 NaN NaN NaN
14 1.053086 NaN NaN NaN

Pandas update values in a multi-index dataframe

How can I edit a values of a multi-index dataframe? If it was a non-multi-index dataframe, I know I could do this: df.at[0,'foo'] = 12.3.
Also, this does not work: df.loc[0]['foo']['a'] = 12.3.
Consider a multi-index column dataframe.
colnames = [
['foo', 'foo', 'foo', 'po', 'po', 'po', 'di', 'di', 'di'],
['a', 'b', 'c', 'a', 'b', 'c', 'a', 'b', 'c']
]
df = pd.DataFrame(columns=colnames, index=arange(5))
display(df)
foo po di
a b c a b c a b c
0 NaN NaN NaN NaN NaN NaN NaN NaN NaN
1 NaN NaN NaN NaN NaN NaN NaN NaN NaN
2 NaN NaN NaN NaN NaN NaN NaN NaN NaN
3 NaN NaN NaN NaN NaN NaN NaN NaN NaN
4 NaN NaN NaN NaN NaN NaN NaN NaN NaN
Use tuples for select MultiIndex in columns:
df.loc[0, ('foo','a')] = 12.3
print (df)
foo po di
a b c a b c a b c
0 12.3 NaN NaN NaN NaN NaN NaN NaN NaN
1 NaN NaN NaN NaN NaN NaN NaN NaN NaN
2 NaN NaN NaN NaN NaN NaN NaN NaN NaN
3 NaN NaN NaN NaN NaN NaN NaN NaN NaN
4 NaN NaN NaN NaN NaN NaN NaN NaN NaN
If need more complicated updating use slicers:
idx = pd.IndexSlice
df.loc[0, idx['foo', ['b','c']]] = 12.3
print (df)
foo po di
a b c a b c a b c
0 NaN 12.3 12.3 NaN NaN NaN NaN NaN NaN
1 NaN NaN NaN NaN NaN NaN NaN NaN NaN
2 NaN NaN NaN NaN NaN NaN NaN NaN NaN
3 NaN NaN NaN NaN NaN NaN NaN NaN NaN
4 NaN NaN NaN NaN NaN NaN NaN NaN NaN
df.loc[0, idx[:, ['b','c']]] = 12.3
print (df)
foo po di
a b c a b c a b c
0 NaN 12.3 12.3 NaN 12.3 12.3 NaN 12.3 12.3
1 NaN NaN NaN NaN NaN NaN NaN NaN NaN
2 NaN NaN NaN NaN NaN NaN NaN NaN NaN
3 NaN NaN NaN NaN NaN NaN NaN NaN NaN
4 NaN NaN NaN NaN NaN NaN NaN NaN NaN
df.loc[:, idx[['po','di'], 'a']] = 12.3
print (df)
foo po di
a b c a b c a b c
0 NaN NaN NaN 12.3 NaN NaN 12.3 NaN NaN
1 NaN NaN NaN 12.3 NaN NaN 12.3 NaN NaN
2 NaN NaN NaN 12.3 NaN NaN 12.3 NaN NaN
3 NaN NaN NaN 12.3 NaN NaN 12.3 NaN NaN
4 NaN NaN NaN 12.3 NaN NaN 12.3 NaN NaN

Pandas- How to append a transpose of dataframe to another dataframe as column headers?

I need to add DF1 values as column in DF2
DataFrame1
DataFrame2 (in which append operation is required)
Required DataFrame - DF3
Try pd.concat with an empty dataframe consisting only of headers. Here's a demo -
df1
A B
0 -0.820067 -0.078793
1 -0.341793 -0.301040
2 -0.122264 1.163896
3 -1.693027 0.147647
4 -1.322206 1.839631
5 0.902077 0.334976
6 0.628941 -1.252080
7 0.607116 -0.588056
8 0.564448 0.096036
9 -0.863496 0.345668
df2
HeaderName
0 XYZ
1 ABC
2 SRT
3 FFF
pd.concat([df1, pd.DataFrame(columns=df2.HeaderName)], 1)
A B XYZ ABC SRT FFF
0 -0.820067 -0.078793 NaN NaN NaN NaN
1 -0.341793 -0.301040 NaN NaN NaN NaN
2 -0.122264 1.163896 NaN NaN NaN NaN
3 -1.693027 0.147647 NaN NaN NaN NaN
4 -1.322206 1.839631 NaN NaN NaN NaN
5 0.902077 0.334976 NaN NaN NaN NaN
6 0.628941 -1.252080 NaN NaN NaN NaN
7 0.607116 -0.588056 NaN NaN NaN NaN
8 0.564448 0.096036 NaN NaN NaN NaN
9 -0.863496 0.345668 NaN NaN NaN NaN
Use DataFrame.join:
df2 = df1.join(pd.DataFrame(columns=df2['HeaderName']))
Or assign:
df2 = df1.assign(**pd.Series(index=df2['HeaderName']))
We can using reindex
df1.reindex(columns=list(df1)+df2.HeaderName.tolist())
Out[754]:
A B XYZ ABC SRT FFF
0 -0.820067 -0.078793 NaN NaN NaN NaN
1 -0.341793 -0.301040 NaN NaN NaN NaN
2 -0.122264 1.163896 NaN NaN NaN NaN
3 -1.693027 0.147647 NaN NaN NaN NaN
4 -1.322206 1.839631 NaN NaN NaN NaN
5 0.902077 0.334976 NaN NaN NaN NaN
6 0.628941 -1.252080 NaN NaN NaN NaN
7 0.607116 -0.588056 NaN NaN NaN NaN
8 0.564448 0.096036 NaN NaN NaN NaN
9 -0.863496 0.345668 NaN NaN NaN NaN

Subtracting column from dataframe

Hi I'm trying to subtract values of one of DataFrame columns from whole DataFrame. Intuitively this seems like a non-problem for me, but somehow I can't figure it out.
Here is the code:
import pandas as pd
x = pd.DataFrame({
"a": range(1, 10),
"b": range(2, 11),
"c": range(11, 20)
})
print x - x['b']
And what I get is surprisingly:
0 1 2 3 4 5 6 7 8 a b c
0 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
1 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
2 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
3 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
4 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
5 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
6 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
7 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
8 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
Instead of DataFrame with columns: (a-b), (b-b), (c-b).
I just started playing with Python. Can you tell me what am I missing?
Thanks!
Try:
x.subtract(x['b'], axis=0)
a b c
0 -1 0 9
1 -1 0 9
2 -1 0 9
3 -1 0 9
4 -1 0 9
5 -1 0 9
6 -1 0 9
7 -1 0 9
8 -1 0 9
See docs for details on the axis=0 parameter, which ensures that the index of x['B'] aligns with the DataFrame index, and not the columns as per default.
To make the - operator work, you'd have to:
(x.T - x['b']).T

Categories