I have a the following pandas data frame with the index on the left:
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
A17 a b 1 AUG) NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
nn6 c d 2 POS) e f 2 Hi)
AZV NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
JFK a b 4 UUI) c v 8 Yo) t f 9 po)
I'm looking to re-shape it to:
0 1 2 3
A17 a b 1 AUG)
nn6 c d 2 POS)
nn6 e f 2 Hi)
AZV NaN NaN NaN NaN
JFK a b 4 UUI)
JFK c v 8 Yo)
JFK t f 9 po
I have tried reshape() and used itertools to iterate over the columns but still can't seem to get it.
Basically, each time a ) is encountered then break to a new line.
The real table has over 150 columns.
thanks
Another option that doesn't require iterating over rows (which can be very slow if there are many) is to do the following
[ins] In [1]: df
Out[1]:
0 1 2 3 4 5 6 7
A17 a b 1 AUG) NaN NaN NaN NaN
nn6 c d 2 POS) e f 2 HI)
AVZ NaN NaN NaN NaN NaN NaN NaN
[ins] In [2]: joined = df.apply(lambda x: ' '.join([str(xi) for xi in x]), axis=1)
[ins] In [4]: split = joined.str.split(')', expand=True).reset_index(drop=False).melt(id_vars='index')
[ins] In [6]: split.drop('variable', axis=1, inplace=True)
[ins] In [7]: split
Out[7]:
index value
0 A17 a b 1 AUG
1 nn6 c d 2 POS
2 AVZ nan nan nan nan nan nan nan
3 A17 nan nan nan nan
4 nn6 e f 2 HI
5 AVZ None
6 A17 None
7 nn6
8 AVZ None
[ins] In [8]: sel = split['value'].str.strip().str.len() > 0
[ins] In [9]: split = split.loc[sel, :]
[ins] In [9]: split
Out[9]:
index value
0 A17 a b 1 AUG
1 nn6 c d 2 POS
2 AVZ nan nan nan nan nan nan nan
3 A17 nan nan nan nan
4 nn6 e f 2 HI
[ins] In [10]: out = split['value'].str.strip().str.split(' ', expand=True)
[ins] In [11]: out.index = split['index']
[ins] In [12]: out
Out[12]:
0 1 2 3 4 5 6
index
A17 a b 1 AUG None None None
nn6 c d 2 POS None None None
AVZ nan nan nan nan nan nan nan
A17 nan nan nan nan None None None
nn6 e f 2 HI None None None
and then it's a matter of dropping the 4th to 6th column which is simple.
I added some of the output so that you can see what's happening in each step.
I think an efficent way to concat the values would be to chunk the dataframe into 4 equal parts and re-concat it along the index.
The issue here is the column names which we can dynamically rename inside the concat statement.
import numpy as np
lst = np.array_split([i for i in range(len(df.columns))],4)
[array([0, 1, 2, 3]),
array([4, 5, 6, 7]),
array([ 8, 9, 10, 11]),
array([12, 13, 14])]
dfs = pd.concat( [
df.iloc[:,i].rename(columns=
dict(zip(df.iloc[:,i].columns,range(4)))
)
for i in lst
]).dropna(how='all')
print(dfs)
0 1 2 3
A17 a b 1.0 AUG)
nn6 c d 2.0 POS)
JFK a b 4.0 UUI)
nn6 e f 2.0 Hi)
JFK c v 8.0 Yo)
JFK t f 9.0 po)
the only diff here is that your missing a row from your desired output due to it being na.
we can do a union with combine_first to get the delta between the two dataframes.
dfs = dfs.combine_first(df.iloc[:,:0])
print(dfs)
0 1 2 3
A17 a b 1.0 AUG)
AZV NaN NaN NaN NaN
JFK a b 4.0 UUI)
JFK c v 8.0 Yo)
JFK t f 9.0 po)
nn6 c d 2.0 POS)
nn6 e f 2.0 Hi)
There are other options, like slicing columns and appending, but this is pretty straightforward.
output = []
for index, row in df.iterrows():
r = row.dropna().values
if len(r) <= 4:
output.append([index,*r])
else:
for x in np.reshape(r, (int(len(r)/4),4)):
output.append([index,*x])
pd.DataFrame(output).set_index(0)
Related
Hi I have the following dataframe that is ~1,400,000 rows:
x = pd.DataFrame({'ID':['A','B','D','D','F'], 'start1':[1,2,3,4,5], 'start2':[12,11,10,6,7], 'start3':[1,6,2,4,5], 'start4':[5,4,2,3,1], 'start5':[0,0,0,0,0], 'end1':[2,3,4,7,9] })
ID start1 start2 start3 start4 start5 end1
A 1 12 1 5 0 2
B 2 11 6 4 0 3
D 3 10 2 2 0 4
D 4 6 4 3 0 7
F 5 7 5 1 0 9
I'm looking to collapse all rows that contain column headers 'start' or 'end' into the following format:
desired output:
ID start end
A 1 NaN
A 12 NAN
A 1 NAN
A 5 NaN
A 0 NaN
A NaN 2
B 2 NaN
B 11 NaN
B 6 NaN
B 4 NaN
B 0 NaN
B 3 NaN
...
F 1 NaN
F 0 NaN
F NaN 9
I have tried:
joined = df2.apply(lambda x: ' '.join([str(xi) for xi in x]), axis=1)
split = joined.str.split('', expand=True).reset_index(drop=False).melt(id_vars='index')
However this seems to use up all my memory and the environment crashes.
Any help would be great
Try melt the start columns and concat
(pd.concat([x.iloc[:,:-1].melt('ID', value_name='start')
.sort_values(['ID','variable']).drop('variable',axis=1),
x[['ID','end1']]
])
.sort_values('ID', kind='mergesort')
)
Output:
ID start end1
0 A 1.0 NaN
5 A 12.0 NaN
10 A 1.0 NaN
15 A 5.0 NaN
20 A 0.0 NaN
0 A NaN 2.0
1 B 2.0 NaN
6 B 11.0 NaN
11 B 6.0 NaN
16 B 4.0 NaN
21 B 0.0 NaN
1 B NaN 3.0
2 D 3.0 NaN
3 D 4.0 NaN
7 D 10.0 NaN
8 D 6.0 NaN
12 D 2.0 NaN
13 D 4.0 NaN
17 D 2.0 NaN
18 D 3.0 NaN
22 D 0.0 NaN
23 D 0.0 NaN
2 D NaN 4.0
3 D NaN 7.0
4 F 5.0 NaN
9 F 7.0 NaN
14 F 5.0 NaN
19 F 1.0 NaN
24 F 0.0 NaN
4 F NaN 9.0
Remember that you are trying to duplicate a large amount of data here, so you need to be careful.
How about this?
import numpy as np
out = pd.DataFrame(columns = ['ID', 'start', 'end'])
for col in x.columns:
if 'start'in col:
out_col = 'start'
if 'end' in col:
out_col = 'end'
if 'ID' not in col:
temp = x[['ID', col]].rename(columns = {col:out_col})
out = pd.concat([out,temp])
Output:
ID start end
0 A 1 NaN
0 A 0 NaN
0 A NaN 2
0 A 12 NaN
0 A 5 NaN
0 A 1 NaN
1 B 0 NaN
1 B 4 NaN
1 B NaN 3
1 B 6 NaN
1 B 11 NaN
1 B 2 NaN
2 D 10 NaN
2 D 0 NaN
2 D 2 NaN
3 D 4 NaN
3 D NaN 7
2 D NaN 4
2 D 2 NaN
3 D 3 NaN
3 D 4 NaN
2 D 3 NaN
3 D 6 NaN
3 D 0 NaN
4 F 5 NaN
4 F 1 NaN
4 F 7 NaN
4 F 5 NaN
4 F 0 NaN
4 F NaN 9
You can merge all columns into one by .ravel()
So: add end1 and Id to another variable
end1values = x['end1']a
idvalues = x['ID']
Remove end and Id from data set:
x.drop('end1',
axis='columns', inplace=True)
x.drop('ID',
axis='columns', inplace=True)
use Ravel for starts:
df = pd.DataFrame({'start':x.values.ravel()})
Add end1 + ID
df['ID'] = idvalues
df['end'] = end1values
Result:
From the original data, there are duplicated data. The duplicates with different DB have to concat to the back of the former one.Is there any way to merge two tables into one as shown below by comparing between data?
From the original data using drop.duplicates and duplicated, i get two tables and wanted to compare them using dictionaries, but by making rows as dictionaries in both the table, the keys are the same in every dictionary which i can't merge them together.
This is the original data given
DB TITLE ISSN IBSN
0 M a 1 NaN
1 M d 1 NaN
2 M c 1 NaN
3 N b 1 NaN
4 N a 1 NaN
5 N d 1 NaN
6 O c 1 NaN
7 O e 1 NaN
8 O a 1 NaN
9 O b 1 NaN
By using drop_duplicates and duplicated:
DB TITLE ISSN IBSN DB TITLE ISSN IBSN
0 M a 1 NaN 0 N a 1 NaN
1 M d 1 NaN 1 N d 1 NaN
2 M c 1 NaN 2 O c 1 NaN
3 N b 1 NaN 3 O a 1 NaN
4 O e 1 NaN 4 O b 1 NaN
This is the kind of dictionary i get from the rows:
{'DB': 'N', 'TITLE': 'a', 'ISSN': 1, 'IBSN': 'NaN'}
{'DB': 'M', 'TITLE': 'a', 'ISSN': 1, 'IBSN': 'NaN'}
I expect the output to be
DB TITLE ISSN IBSN DB TITLE ISSN ISBN DB TITLE ISSN IBSN
0 M a 1.0 NaN N a 1.0 NaN O a 1.0 NaN
1 N b 1.0 NaN O b 1.0 NaN NaN NaN NaN NaN
2 M d 1.0 NaN N d 1.0 NaN NaN NaN NaN NaN
3 M c 1.0 NaN O c 1.0 NaN NaN NaN NaN NaN
4 O e 1.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN
The order of 'TITLE' in the column is not important but the DB have to be sorted alphabetically from left to right.
I think the simplest way to do this is using cumcount to segregate sub-groups, then use concat with join='outer':
grps = [
g.set_index('TITLE') for _, g in df.groupby(df.groupby('TITLE').cumcount())
]
pd.concat(grps, join='outer', axis=1, sort=True)
DB ISSN IBSN DB ISSN IBSN DB ISSN IBSN
a M 1 NaN N 1.0 NaN O 1.0 NaN
b N 1 NaN O 1.0 NaN NaN NaN NaN
c M 1 NaN O 1.0 NaN NaN NaN NaN
d M 1 NaN N 1.0 NaN NaN NaN NaN
e O 1 NaN NaN NaN NaN NaN NaN NaN
If you need "TITLE" too, use set_index with drop=False:
grps = [
g.set_index('TITLE', drop=False)
for _, g in df.groupby(df.groupby('TITLE').cumcount())
]
pd.concat(grps, join='outer', axis=1, sort=True)
DB TITLE ISSN IBSN DB TITLE ISSN IBSN DB TITLE ISSN IBSN
a M a 1 NaN N a 1.0 NaN O a 1.0 NaN
b N b 1 NaN O b 1.0 NaN NaN NaN NaN NaN
c M c 1 NaN O c 1.0 NaN NaN NaN NaN NaN
d M d 1 NaN N d 1.0 NaN NaN NaN NaN NaN
e O e 1 NaN NaN NaN 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
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