This question already has answers here:
How to remove nan value while combining two column in Panda Data frame?
(5 answers)
Closed 4 years ago.
I have two columns containing strings and NAs and I want to combine them into 1. I feel this should be fairly simple but cannot seem to get it to work or find the answer on here. Below is the result I am after.
S1 S2 S
A Nan A
A Nan A
A Nan A
A Nan A
Nan C C
Nan C C
Nan C C
Nan C C
Nan Nan Nan
Nan Nan Nan
Nan Nan Nan
B Nan B
B Nan B
B Nan B
B Nan B
B Nan B
I thought df['S'] = df['S1']+ df['S2'] would work but no.
Really feel like there will be an obvious fix, thanks in advance.
Use combine_first:
df['S_new'] = df['S1'].combine_first(df['S2'])
print (df)
S1 S2 S S_new
0 A NaN A A
1 A NaN A A
2 A NaN A A
3 A NaN A A
4 NaN C C C
5 NaN C C C
6 NaN C C C
7 NaN C C C
8 NaN NaN NaN NaN
9 NaN NaN NaN NaN
10 NaN NaN NaN NaN
11 B NaN B B
12 B NaN B B
13 B NaN B B
14 B NaN B B
15 B NaN B B
Related
This question already has answers here:
How to implement sql coalesce in pandas
(5 answers)
Closed 1 year ago.
I am trying to create a column in my dataframe which searches each column and checks if the value of at specific row is null or not, if it is not the new column will contain this value, otherwise it will skip it. It is not possible that two columns contains a non null value.
For example:
A B C D E
NaN NaN NaN NaN a
b NaN NaN NaN NaN
NaN NaN NaN NaN NaN
My expected output:
A B C D E new_column
NaN NaN NaN NaN a a
b NaN NaN NaN NaN b
NaN NaN NaN NaN NaN NaN
You can bfill horizontally and then select the first column:
df['new_column'] = df.bfill(axis=1).iloc[:, 0]
Output:
>>> df
A B C D E new_column
0 NaN NaN NaN NaN a a
1 b NaN NaN NaN NaN b
2 NaN NaN NaN NaN NaN NaN
having a DataFrame with e.g. 10 columns (a, b, c...) and another smaller one with just let's say 3 of them (d, f, h), what is the 'best' way to copy the columns from the second DataFrame to the first?
The below seems to do the trick but I'm wondering if I should use join, merge or something else instead (for better performance/cleaner code)?
dfOutput = pd.DataFrame(columns=['a','b','c','d','e','f','g','h','i','j'])
melted = pd.DataFrame([[1,2,3],[4,5,6],[7,8,9]],columns=['d','h','i'])
dfOutput[melted.columns] = melted[melted.columns]
I believe you need df.merge() and df.reindex():
melted.merge(dfOutput,on=['d','h','i'],how='left').reindex(dfOutput.columns,axis=1)
a b c d e f g h i j
0 NaN NaN NaN 1 NaN NaN NaN 2 3 NaN
1 NaN NaN NaN 4 NaN NaN NaN 5 6 NaN
2 NaN NaN NaN 7 NaN NaN NaN 8 9 NaN
you can reassign this to the first dataframe :
dfOutput = melted.merge(dfOutput,on=['d','h','i'],how='left').reindex(dfOutput.columns,axis=1)
Scenario 2 : If you already have data in certain columns , use dfOutput.update(melted) to update the first dataframe with the second:
For example:
dfOutput:
a b c d e f g h i j
0 NaN NaN NaN 1 NaN NaN NaN NaN NaN NaN
1 NaN NaN NaN 2 NaN NaN NaN NaN NaN NaN
2 NaN NaN NaN 3 NaN NaN NaN NaN NaN NaN
melted:
d h i
0 5 6 7
1 4 8 6
2 7 4 9
>>dfOutput.update(melted)
>>dfOutput
a b c d e f g h i j
0 NaN NaN NaN 5 NaN NaN NaN 6 7 NaN
1 NaN NaN NaN 4 NaN NaN NaN 8 6 NaN
2 NaN NaN NaN 7 NaN NaN NaN 4 9 NaN
Consider the below pandas Series object,
index = list('abcdabcdabcd')
df = pd.Series(np.arange(len(index)), index = index)
My desired output is,
a b c d
0 0 1 2 3
1 4 5 6 7
2 8 9 10 11
I have put some effort with pd.pivot_table, pd.unstack and probably the solution lies with correct use of one of them. The closest i have reached is
df.reset_index(level = 1).unstack(level = 1)
but this does not gives me the output i my looking for
// here is something even closer to the desired output, but i am not able to handle the index grouping.
df.to_frame().set_index(df1.values, append = True, drop = False).unstack(level = 0)
a b c d
0 0.0 NaN NaN NaN
1 NaN 1.0 NaN NaN
2 NaN NaN 2.0 NaN
3 NaN NaN NaN 3.0
4 4.0 NaN NaN NaN
5 NaN 5.0 NaN NaN
6 NaN NaN 6.0 NaN
7 NaN NaN NaN 7.0
8 8.0 NaN NaN NaN
9 NaN 9.0 NaN NaN
10 NaN NaN 10.0 NaN
11 NaN NaN NaN 11.0
A bit more general solution using cumcount to get new index values, and pivot to do the reshaping:
# Reset the existing index, and construct the new index values.
df = df.reset_index()
df.index = df.groupby('index').cumcount()
# Pivot and remove the column axis name.
df = df.pivot(columns='index', values=0).rename_axis(None, axis=1)
The resulting output:
a b c d
0 0 1 2 3
1 4 5 6 7
2 8 9 10 11
Here is a way that will work if the index is always cycling in the same order, and you know the "period" (in this case 4):
>>> pd.DataFrame(df.values.reshape(-1,4), columns=list('abcd'))
a b c d
0 0 1 2 3
1 4 5 6 7
2 8 9 10 11
>>>
I have a wide dataframe that I want to stack and pivot and can't quite figure out how to do it.
Here is what I am starting with
testdf = pd.DataFrame({"Topic":["A","B","B","C","A"],
"Org":[1,1,2,3,5,],
"DE1":["a","c","d","e","f"],
"DE2":["b","c","a","d","h"],
"DE3":["a","c","b","e","f"] })
testdf
Out[40]:
DE1 DE2 DE3 Org Topic
0 a b a 1 A
1 c c c 1 B
2 d a b 2 B
3 e d e 3 C
4 f h f 5 A
What I would like to do is pivot the table so that the column values for Org are the Column names and the column values for each name are the matching values from D1,D2 and D3 and finally have Topic as the index. Is this even possible?
EDIT: As Randy C pointed out, if I use pivot I can get the following;
testdf.pivot(index = "Topic",columns = "Org")
Out[44]:
DE1 DE2 DE3
Org 1 2 3 5 1 2 3 5 1 2 3 5
Topic
A a NaN NaN f b NaN NaN h a NaN NaN f
B c d NaN NaN c a NaN NaN c b NaN NaN
C NaN NaN e NaN NaN NaN d NaN NaN NaN e NaN
Which is close, but I would like to have it so that the DE values are "stacked" and not wide. The result would look like;
Org 1 2 3 5
Topic
A a NaN NaN f
A b NaN NaN h
A a NaN NaN f
B c d NaN NaN
B c a NaN NaN
B c b NaN NaN
C NaN NaN e NaN
C NaN NaN d NaN
C NaN NaN e NaN
Perhaps:
In[249]: testdf.pivot("Org","Topic").T
Out[249]:
Org 1 2 3 5
Topic
DE1 A a NaN NaN f
B c d NaN NaN
C NaN NaN e NaN
DE2 A b NaN NaN h
B c a NaN NaN
C NaN NaN d NaN
DE3 A a NaN NaN f
B c b NaN NaN
C NaN NaN e NaN
It's not 100% clear to me what your desired output is, but as best I can understand it, .pivot() does seem to be at least close to what you're looking for:
In [8]: testdf.pivot("Topic", "Org")
Out[8]:
DE1 DE2 DE3
Org 1 2 3 5 1 2 3 5 1 2 3 5
Topic
A a NaN NaN f b NaN NaN h a NaN NaN f
B c d NaN NaN c a NaN NaN c b NaN NaN
C NaN NaN e NaN NaN NaN d NaN NaN NaN e NaN
Edit: found my answer here: Building a hierarchically indexed DataFrame from existing DataFrames
Turns out I need to create a matching MultiIndex with the higher levels fixed
Original:
I confess, I don't understand the merges and joins yet, but I'm not sure they're what I want.
I have a DataFrame that has a single index, and a DataFrame that has a MultiIndex, the last level of which is the same as the single-index DataFrame.
I am trying to copy/graft the contents in:
In [1]: import pandas as pd
In [2]: import numpy as np
In [3]: import itertools
In [4]:
In [4]: inner = ('a','b')
In [5]: outer = ((10,20), (1,2))
In [6]: cols = ('one','two','three','four')
In [7]:
In [7]: sngl = pd.DataFrame(np.random.randn(2,4), index=inner, columns=cols)
In [8]:
In [8]: index_tups = list(itertools.product(*(outer + (inner,))))
In [9]: index_mult = pd.MultiIndex.from_tuples(index_tups)
In [10]: mult = pd.DataFrame(index=index_mult, columns=cols)
In [11]:
In [11]: sngl
Out[11]:
one two three four
a 2.946876 -0.751171 2.306766 0.323146
b 0.192558 0.928031 1.230475 -0.256739
In [12]: mult
Out[12]:
one two three four
10 1 a NaN NaN NaN NaN
b NaN NaN NaN NaN
2 a NaN NaN NaN NaN
b NaN NaN NaN NaN
20 1 a NaN NaN NaN NaN
b NaN NaN NaN NaN
2 a NaN NaN NaN NaN
b NaN NaN NaN NaN
In [13]:
In [13]: mult.ix[(10,1)] = sngl
In [14]:
In [14]: mult
Out[14]:
one two three four
10 1 a NaN NaN NaN NaN
b NaN NaN NaN NaN
2 a NaN NaN NaN NaN
b NaN NaN NaN NaN
20 1 a NaN NaN NaN NaN
b NaN NaN NaN NaN
2 a NaN NaN NaN NaN
b NaN NaN NaN NaN
In [15]:
What am I doing wrong?
Edit: it works when I do index by index, but that's not the pandas way, surely:
In [15]: mult.ix[(10,1,'a')] = sngl.ix['a']
In [16]: mult
Out[16]:
one two three four
10 1 a 2.946876 -0.7511706 2.306766 0.3231457
b NaN NaN NaN NaN
2 a NaN NaN NaN NaN
b NaN NaN NaN NaN
20 1 a NaN NaN NaN NaN
b NaN NaN NaN NaN
2 a NaN NaN NaN NaN
b NaN NaN NaN NaN
.ix and .loc are equivalent in this example (just more explicit)
In [48]: nm = mult.reset_index().set_index('level_2')
In [49]: nm
Out[49]:
level_0 level_1 one two three four
level_2
a 10 1 NaN NaN NaN NaN
b 10 1 NaN NaN NaN NaN
a 10 2 NaN NaN NaN NaN
b 10 2 NaN NaN NaN NaN
a 20 1 NaN NaN NaN NaN
b 20 1 NaN NaN NaN NaN
a 20 2 NaN NaN NaN NaN
b 20 2 NaN NaN NaN NaN
This should probably work with a series on the rhs; this might be a buglet
In [50]: nm.loc['a',sngl.columns] = sngl.loc['a'].values
In [51]: nm
Out[51]:
level_0 level_1 one two three four
level_2
a 10 1 0.3738456 -0.2261926 -1.205177 0.08448757
b 10 1 NaN NaN NaN NaN
a 10 2 0.3738456 -0.2261926 -1.205177 0.08448757
b 10 2 NaN NaN NaN NaN
a 20 1 0.3738456 -0.2261926 -1.205177 0.08448757
b 20 1 NaN NaN NaN NaN
a 20 2 0.3738456 -0.2261926 -1.205177 0.08448757
b 20 2 NaN NaN NaN NaN
In [52]: nm.reset_index().set_index(['level_0','level_1','level_2'])
Out[52]:
one two three four
level_0 level_1 level_2
10 1 a 0.3738456 -0.2261926 -1.205177 0.08448757
b NaN NaN NaN NaN
2 a 0.3738456 -0.2261926 -1.205177 0.08448757
b NaN NaN NaN NaN
20 1 a 0.3738456 -0.2261926 -1.205177 0.08448757
b NaN NaN NaN NaN
2 a 0.3738456 -0.2261926 -1.205177 0.08448757
b NaN NaN NaN NaN