Porównaj dwie ramki DataFrame i wyświetl ich różnice obok siebie


162

Próbuję dokładnie podkreślić, co zmieniło się między dwiema ramkami danych.

Załóżmy, że mam dwie ramki danych Python Pandas:

"StudentRoster Jan-1":
id   Name   score                    isEnrolled           Comment
111  Jack   2.17                     True                 He was late to class
112  Nick   1.11                     False                Graduated
113  Zoe    4.12                     True       

"StudentRoster Jan-2":
id   Name   score                    isEnrolled           Comment
111  Jack   2.17                     True                 He was late to class
112  Nick   1.21                     False                Graduated
113  Zoe    4.12                     False                On vacation

Moim celem jest utworzenie tabeli HTML, która:

  1. Identyfikuje wiersze, które uległy zmianie (mogą to być int, float, boolean, string)
  2. Wyprowadza wiersze z takimi samymi, OLD i NEW wartościami (najlepiej w tabeli HTML), aby konsument mógł wyraźnie zobaczyć, co zmieniło się między dwiema ramkami danych:

    "StudentRoster Difference Jan-1 - Jan-2":  
    id   Name   score                    isEnrolled           Comment
    112  Nick   was 1.11| now 1.21       False                Graduated
    113  Zoe    4.12                     was True | now False was "" | now   "On   vacation"

Przypuszczam, że mógłbym zrobić porównanie wiersz po wierszu i kolumna po kolumnie, ale czy istnieje prostszy sposób?


Od pandy 1.1 możesz to łatwo zrobić za pomocą jednego wywołania funkcji -df.compare .
cs95

Odpowiedzi:


153

Pierwsza część jest podobna do Constantine, możesz uzyskać wartość logiczną określającą, które wiersze są puste *:

In [21]: ne = (df1 != df2).any(1)

In [22]: ne
Out[22]:
0    False
1     True
2     True
dtype: bool

Następnie możemy zobaczyć, które wpisy się zmieniły:

In [23]: ne_stacked = (df1 != df2).stack()

In [24]: changed = ne_stacked[ne_stacked]

In [25]: changed.index.names = ['id', 'col']

In [26]: changed
Out[26]:
id  col
1   score         True
2   isEnrolled    True
    Comment       True
dtype: bool

Tutaj pierwszy wpis to indeks, a drugi kolumny, które zostały zmienione.

In [27]: difference_locations = np.where(df1 != df2)

In [28]: changed_from = df1.values[difference_locations]

In [29]: changed_to = df2.values[difference_locations]

In [30]: pd.DataFrame({'from': changed_from, 'to': changed_to}, index=changed.index)
Out[30]:
               from           to
id col
1  score       1.11         1.21
2  isEnrolled  True        False
   Comment     None  On vacation

* Uwaga: ważne jest, df1i df2dzielić ten sam indeks tutaj. Aby przezwyciężyć tę niejednoznaczność, możesz upewnić się, że patrzysz tylko na wspólne etykiety przy użyciu df1.index & df2.index, ale myślę, że zostawię to jako ćwiczenie.


2
Uważam, że „dzielenie tego samego indeksu” oznacza „upewnij się, że indeks jest posortowany” ... to porówna wszystko, co jest na pierwszym miejscu, df1z tym, co jest na pierwszym miejscu df2, niezależnie od wartości indeksu. JFYI na wypadek, gdybym nie był jedyną osobą, dla której to nie było oczywiste. ; D Dzięki!
dmn

12
Jeśli wynik jest równy nanw obu df1 i df1, ta funkcja zgłosi zmianę z nanna nan. To dlatego, że np.nan != np.nanwraca True.
James Owers,

2
@kungfujam ma rację. Ponadto, jeśli porównywane wartości są Brak, również tam wystąpią fałszywe różnice
FistOfFury,

Dla jasności - ilustruję problem tym rozwiązaniem i zapewniam łatwą w użyciu funkcję, która rozwiązuje problem poniżej
James Owers

1
[„row”, „col”] jest preferowane niż [„id”, „col”] jako zmienione.index.names, ponieważ nie są to identyfikatory, ale wiersze.
naoki fujita

88

Podkreślenie różnicy między dwoma DataFrames

Możliwe jest użycie właściwości stylu DataFrame do podświetlenia koloru tła komórek, w których występuje różnica.

Na podstawie przykładowych danych z oryginalnego pytania

Pierwszym krokiem jest poziome konkatenowanie ramek DataFrames z concatfunkcją i rozróżnianie każdej klatki za pomocą keysparametru:

df_all = pd.concat([df.set_index('id'), df2.set_index('id')], 
                   axis='columns', keys=['First', 'Second'])
df_all

wprowadź opis obrazu tutaj

Prawdopodobnie łatwiej jest zamienić poziomy kolumn i umieścić obok siebie te same nazwy kolumn:

df_final = df_all.swaplevel(axis='columns')[df.columns[1:]]
df_final

wprowadź opis obrazu tutaj

Teraz znacznie łatwiej jest dostrzec różnice w ramkach. Ale możemy pójść dalej i użyć tej stylewłaściwości do wyróżnienia komórek, które są różne. W tym celu definiujemy funkcję niestandardową, którą można zobaczyć w tej części dokumentacji .

def highlight_diff(data, color='yellow'):
    attr = 'background-color: {}'.format(color)
    other = data.xs('First', axis='columns', level=-1)
    return pd.DataFrame(np.where(data.ne(other, level=0), attr, ''),
                        index=data.index, columns=data.columns)

df_final.style.apply(highlight_diff, axis=None)

wprowadź opis obrazu tutaj

Podświetli to komórki, w których obie mają brakujące wartości. Możesz je wypełnić lub podać dodatkową logikę, aby nie były podświetlane.


1
Czy wiesz, jak można pokolorować „pierwszy” i „drugi” różnymi kolorami?
aturegano,

1
Czy można wybrać tylko różne wiersze? W takim przypadku jak wybrać drugi i trzeci wiersz bez wybierania pierwszego wiersza (111)?
shantanuo

1
@shantanuo, tak, po prostu edytuj ostatnią metodę nadf_final[(df != df2).any(1)].style.apply(highlight_diff, axis=None)
anmol

3
Ta implementacja zajmuje więcej czasu podczas porównywania ramek danych z 26 tys. Wierszy i 400 kolumnami. Czy jest jakiś sposób, aby to przyspieszyć?
codelord

42

Ta odpowiedź po prostu rozszerza @Andy Hayden, czyniąc ją odporną na działanie pól numerycznych nani opakowując ją w funkcję.

import pandas as pd
import numpy as np


def diff_pd(df1, df2):
    """Identify differences between two pandas DataFrames"""
    assert (df1.columns == df2.columns).all(), \
        "DataFrame column names are different"
    if any(df1.dtypes != df2.dtypes):
        "Data Types are different, trying to convert"
        df2 = df2.astype(df1.dtypes)
    if df1.equals(df2):
        return None
    else:
        # need to account for np.nan != np.nan returning True
        diff_mask = (df1 != df2) & ~(df1.isnull() & df2.isnull())
        ne_stacked = diff_mask.stack()
        changed = ne_stacked[ne_stacked]
        changed.index.names = ['id', 'col']
        difference_locations = np.where(diff_mask)
        changed_from = df1.values[difference_locations]
        changed_to = df2.values[difference_locations]
        return pd.DataFrame({'from': changed_from, 'to': changed_to},
                            index=changed.index)

Tak więc z twoimi danymi (lekko edytowanymi, aby mieć NaN w kolumnie wyników):

import sys
if sys.version_info[0] < 3:
    from StringIO import StringIO
else:
    from io import StringIO

DF1 = StringIO("""id   Name   score                    isEnrolled           Comment
111  Jack   2.17                     True                 "He was late to class"
112  Nick   1.11                     False                "Graduated"
113  Zoe    NaN                     True                  " "
""")
DF2 = StringIO("""id   Name   score                    isEnrolled           Comment
111  Jack   2.17                     True                 "He was late to class"
112  Nick   1.21                     False                "Graduated"
113  Zoe    NaN                     False                "On vacation" """)
df1 = pd.read_table(DF1, sep='\s+', index_col='id')
df2 = pd.read_table(DF2, sep='\s+', index_col='id')
diff_pd(df1, df2)

Wynik:

                from           to
id  col                          
112 score       1.11         1.21
113 isEnrolled  True        False
    Comment           On vacation

Dodałem kod, aby zająć się drobnymi różnicami w typie danych, który powodowałby błąd, gdybyś go nie uwzględnił.
Roobie Nuby

A co, jeśli nie mam identycznych wierszy po obu stronach do porównania?
Kishor kumar R

@KishorkumarR następnie powinieneś najpierw wyrównać wiersze, wykrywając dodane wiersze do nowej ramki danych i usunąć wiersze ze starej ramki danych
Sabre

22
import pandas as pd
import io

texts = ['''\
id   Name   score                    isEnrolled                        Comment
111  Jack   2.17                     True                 He was late to class
112  Nick   1.11                     False                           Graduated
113  Zoe    4.12                     True       ''',

         '''\
id   Name   score                    isEnrolled                        Comment
111  Jack   2.17                     True                 He was late to class
112  Nick   1.21                     False                           Graduated
113  Zoe    4.12                     False                         On vacation''']


df1 = pd.read_fwf(io.StringIO(texts[0]), widths=[5,7,25,21,20])
df2 = pd.read_fwf(io.StringIO(texts[1]), widths=[5,7,25,21,20])
df = pd.concat([df1,df2]) 

print(df)
#     id  Name  score isEnrolled               Comment
# 0  111  Jack   2.17       True  He was late to class
# 1  112  Nick   1.11      False             Graduated
# 2  113   Zoe   4.12       True                   NaN
# 0  111  Jack   2.17       True  He was late to class
# 1  112  Nick   1.21      False             Graduated
# 2  113   Zoe   4.12      False           On vacation

df.set_index(['id', 'Name'], inplace=True)
print(df)
#           score isEnrolled               Comment
# id  Name                                        
# 111 Jack   2.17       True  He was late to class
# 112 Nick   1.11      False             Graduated
# 113 Zoe    4.12       True                   NaN
# 111 Jack   2.17       True  He was late to class
# 112 Nick   1.21      False             Graduated
# 113 Zoe    4.12      False           On vacation

def report_diff(x):
    return x[0] if x[0] == x[1] else '{} | {}'.format(*x)

changes = df.groupby(level=['id', 'Name']).agg(report_diff)
print(changes)

wydruki

                score    isEnrolled               Comment
id  Name                                                 
111 Jack         2.17          True  He was late to class
112 Nick  1.11 | 1.21         False             Graduated
113 Zoe          4.12  True | False     nan | On vacation

3
Bardzo fajne rozwiązanie, znacznie bardziej kompaktowe niż moje!
Andy Hayden

1
@AndyHayden: Nie jestem do końca zadowolony z tego rozwiązania; wydaje się działać tylko wtedy, gdy indeks jest indeksem wielopoziomowym. Jeśli spróbuję użyć tylko idjako indeksu, to df.groupby(level='id')wywołuje błąd i nie jestem pewien dlaczego ...
unutbu

19

Napotkałem ten problem, ale znalazłem odpowiedź przed znalezieniem tego postu:

W oparciu o odpowiedź unutbu załaduj swoje dane ...

import pandas as pd
import io

texts = ['''\
id   Name   score                    isEnrolled                       Date
111  Jack                            True              2013-05-01 12:00:00
112  Nick   1.11                     False             2013-05-12 15:05:23
     Zoe    4.12                     True                                  ''',

         '''\
id   Name   score                    isEnrolled                       Date
111  Jack   2.17                     True              2013-05-01 12:00:00
112  Nick   1.21                     False                                
     Zoe    4.12                     False             2013-05-01 12:00:00''']


df1 = pd.read_fwf(io.StringIO(texts[0]), widths=[5,7,25,17,20], parse_dates=[4])
df2 = pd.read_fwf(io.StringIO(texts[1]), widths=[5,7,25,17,20], parse_dates=[4])

... zdefiniuj swoją funkcję diff ...

def report_diff(x):
    return x[0] if x[0] == x[1] else '{} | {}'.format(*x)

Następnie możesz po prostu użyć panelu, aby podsumować:

my_panel = pd.Panel(dict(df1=df1,df2=df2))
print my_panel.apply(report_diff, axis=0)

#          id  Name        score    isEnrolled                       Date
#0        111  Jack   nan | 2.17          True        2013-05-01 12:00:00
#1        112  Nick  1.11 | 1.21         False  2013-05-12 15:05:23 | NaT
#2  nan | nan   Zoe         4.12  True | False  NaT | 2013-05-01 12:00:00

Nawiasem mówiąc, jeśli jesteś w ipython notebooki, może chcesz użyć kolorowego diff funkcję dać kolory w zależności od tego, czy komórki są różne, są równe lub lewo / prawo NULL:

from IPython.display import HTML
pd.options.display.max_colwidth = 500  # You need this, otherwise pandas
#                          will limit your HTML strings to 50 characters

def report_diff(x):
    if x[0]==x[1]:
        return unicode(x[0].__str__())
    elif pd.isnull(x[0]) and pd.isnull(x[1]):
        return u'<table style="background-color:#00ff00;font-weight:bold;">'+\
            '<tr><td>%s</td></tr><tr><td>%s</td></tr></table>' % ('nan', 'nan')
    elif pd.isnull(x[0]) and ~pd.isnull(x[1]):
        return u'<table style="background-color:#ffff00;font-weight:bold;">'+\
            '<tr><td>%s</td></tr><tr><td>%s</td></tr></table>' % ('nan', x[1])
    elif ~pd.isnull(x[0]) and pd.isnull(x[1]):
        return u'<table style="background-color:#0000ff;font-weight:bold;">'+\
            '<tr><td>%s</td></tr><tr><td>%s</td></tr></table>' % (x[0],'nan')
    else:
        return u'<table style="background-color:#ff0000;font-weight:bold;">'+\
            '<tr><td>%s</td></tr><tr><td>%s</td></tr></table>' % (x[0], x[1])

HTML(my_panel.apply(report_diff, axis=0).to_html(escape=False))

(W zwykłym Pythonie, a nie notebooku iPython) czy jest możliwe włączenie my_panel = pd.Panel(dict(df1=df1,df2=df2))funkcji report_diff()? Mam na myśli, czy można to zrobić: print report_diff(df1,df2)i uzyskać takie same wyniki, jak twoja instrukcja drukowania?
edesz

pd.Panel(dict(df1=df1,df2=df2)).apply(report_diff, axis=0)- to jest niesamowite!!!
MaxU

5
Panele są przestarzałe! Masz jakiś pomysł, jak to przenieść?
denfromufa

@denfromufa Próbowałem zaktualizować go w mojej odpowiedzi: stackoverflow.com/a/49038417/7607701
Aaron N. Brock

9

Jeśli twoje dwie ramki danych mają w sobie te same identyfikatory, ustalenie, co się zmieniło, jest w rzeczywistości dość łatwe. Samo zrobienie frame1 != frame2tego da ci boolowską ramkę DataFrame, w której każda Truezawiera dane, które uległy zmianie. Dzięki temu możesz łatwo uzyskać indeks każdego zmienionego wiersza, wykonując changedids = frame1.index[np.any(frame1 != frame2,axis=1)].


6

Inne podejście z użyciem concat i drop_duplicates:

import sys
if sys.version_info[0] < 3:
    from StringIO import StringIO
else:
    from io import StringIO
import pandas as pd

DF1 = StringIO("""id   Name   score                    isEnrolled           Comment
111  Jack   2.17                     True                 "He was late to class"
112  Nick   1.11                     False                "Graduated"
113  Zoe    NaN                     True                  " "
""")
DF2 = StringIO("""id   Name   score                    isEnrolled           Comment
111  Jack   2.17                     True                 "He was late to class"
112  Nick   1.21                     False                "Graduated"
113  Zoe    NaN                     False                "On vacation" """)

df1 = pd.read_table(DF1, sep='\s+', index_col='id')
df2 = pd.read_table(DF2, sep='\s+', index_col='id')
#%%
dictionary = {1:df1,2:df2}
df=pd.concat(dictionary)
df.drop_duplicates(keep=False)

Wynik:

       Name  score isEnrolled      Comment
  id                                      
1 112  Nick   1.11      False    Graduated
  113   Zoe    NaN       True             
2 112  Nick   1.21      False    Graduated
  113   Zoe    NaN      False  On vacation

3

Po pogrzebaniu z odpowiedzią @ journois, byłem w stanie zmusić go do pracy przy użyciu MultiIndex zamiast Panelu z powodu braku panelu .

Najpierw utwórz fikcyjne dane:

df1 = pd.DataFrame({
    'id': ['111', '222', '333', '444', '555'],
    'let': ['a', 'b', 'c', 'd', 'e'],
    'num': ['1', '2', '3', '4', '5']
})
df2 = pd.DataFrame({
    'id': ['111', '222', '333', '444', '666'],
    'let': ['a', 'b', 'c', 'D', 'f'],
    'num': ['1', '2', 'Three', '4', '6'],
})

Następnie zdefiniuj swoją funkcję diff , w tym przypadku użyję tej z jego odpowiedzi report_diffpozostaje taka sama:

def report_diff(x):
    return x[0] if x[0] == x[1] else '{} | {}'.format(*x)

Następnie zamierzam połączyć dane w ramkę danych MultiIndex:

df_all = pd.concat(
    [df1.set_index('id'), df2.set_index('id')], 
    axis='columns', 
    keys=['df1', 'df2'],
    join='outer'
)
df_all = df_all.swaplevel(axis='columns')[df1.columns[1:]]

I na koniec zastosuję report_diffdół każdej grupy kolumn:

df_final.groupby(level=0, axis=1).apply(lambda frame: frame.apply(report_diff, axis=1))

To daje:

         let        num
111        a          1
222        b          2
333        c  3 | Three
444    d | D          4
555  e | nan    5 | nan
666  nan | f    nan | 6

I to wszystko!


3

Rozszerzam odpowiedź @cge, co jest całkiem fajne dla większej czytelności wyniku:

a[a != b][np.any(a != b, axis=1)].join(pd.DataFrame('a<->b', index=a.index, columns=['a<=>b'])).join(
        b[a != b][np.any(a != b, axis=1)]
        ,rsuffix='_b', how='outer'
).fillna('')

Pełny przykład demonstracyjny:

import numpy as np, pandas as pd

a = pd.DataFrame(np.random.randn(7,3), columns=list('ABC'))
b = a.copy()
b.iloc[0,2] = np.nan
b.iloc[1,0] = 7
b.iloc[3,1] = 77
b.iloc[4,2] = 777

a[a != b][np.any(a != b, axis=1)].join(pd.DataFrame('a<->b', index=a.index, columns=['a<=>b'])).join(
        b[a != b][np.any(a != b, axis=1)]
        ,rsuffix='_b', how='outer'
).fillna('')

1

Oto inny sposób korzystania z funkcji wybierania i scalania:

In [6]: # first lets create some dummy dataframes with some column(s) different
   ...: df1 = pd.DataFrame({'a': range(-5,0), 'b': range(10,15), 'c': range(20,25)})
   ...: df2 = pd.DataFrame({'a': range(-5,0), 'b': range(10,15), 'c': [20] + list(range(101,105))})


In [7]: df1
Out[7]:
   a   b   c
0 -5  10  20
1 -4  11  21
2 -3  12  22
3 -2  13  23
4 -1  14  24


In [8]: df2
Out[8]:
   a   b    c
0 -5  10   20
1 -4  11  101
2 -3  12  102
3 -2  13  103
4 -1  14  104


In [10]: # make condition over the columns you want to comapre
    ...: condition = df1['c'] != df2['c']
    ...:
    ...: # select rows from each dataframe where the condition holds
    ...: diff1 = df1[condition]
    ...: diff2 = df2[condition]


In [11]: # merge the selected rows (dataframes) with some suffixes (optional)
    ...: diff1.merge(diff2, on=['a','b'], suffixes=('_before', '_after'))
Out[11]:
   a   b  c_before  c_after
0 -4  11        21      101
1 -3  12        22      102
2 -2  13        23      103
3 -1  14        24      104

Oto to samo ze zrzutu ekranu Jupyter:

wprowadź opis obrazu tutaj


0

pandy> = 1,1: DataFrame.compare

Dzięki pandom 1.1 można zasadniczo powielić dane wyjściowe Teda Petrou za pomocą pojedynczego wywołania funkcji. Przykład zaczerpnięty z dokumentów:

pd.__version__
# '1.1.0.dev0+2004.g8d10bfb6f'

df1.compare(df2)

  score       isEnrolled       Comment             
   self other       self other    self        other
1  1.11  1.21        NaN   NaN     NaN          NaN
2   NaN   NaN        1.0   0.0     NaN  On vacation

Tutaj „self” odnosi się do LHS dataFrame, podczas gdy „inne” to RHS DataFrame. Domyślnie równe wartości są zastępowane przez NaN, więc możesz skupić się tylko na różnicach. Jeśli chcesz wyświetlić równe wartości, użyj

df1.compare(df2, keep_equal=True, keep_shape=True) 

  score       isEnrolled           Comment             
   self other       self  other       self        other
1  1.11  1.21      False  False  Graduated    Graduated
2  4.12  4.12       True  False        NaN  On vacation

Możesz także zmienić oś porównania za pomocą align_axis:

df1.compare(df2, align_axis='index')

         score  isEnrolled      Comment
1 self    1.11         NaN          NaN
  other   1.21         NaN          NaN
2 self     NaN         1.0          NaN
  other    NaN         0.0  On vacation

To porównuje wartości wierszami, a nie kolumnami.


Uwaga: pandy 1.1 są nadal w fazie eksperymentalnej i są dostępne tylko po zbudowaniu piaskownicy deweloperskiej .
cs95

-1

Funkcja znajdująca asymetryczną różnicę między dwiema ramkami danych jest zaimplementowana poniżej: (Na podstawie różnicy zestawu dla pand ) GIST: https://gist.github.com/oneryalcin/68cf25f536a25e65f0b3c84f9c118e03

def diff_df(df1, df2, how="left"):
    """
      Find Difference of rows for given two dataframes
      this function is not symmetric, means
            diff(x, y) != diff(y, x)
      however
            diff(x, y, how='left') == diff(y, x, how='right')

      Ref: /programming/18180763/set-difference-for-pandas/40209800#40209800
    """
    if (df1.columns != df2.columns).any():
        raise ValueError("Two dataframe columns must match")

    if df1.equals(df2):
        return None
    elif how == 'right':
        return pd.concat([df2, df1, df1]).drop_duplicates(keep=False)
    elif how == 'left':
        return pd.concat([df1, df2, df2]).drop_duplicates(keep=False)
    else:
        raise ValueError('how parameter supports only "left" or "right keywords"')

Przykład:

df1 = pd.DataFrame(d1)
Out[1]: 
                Comment  Name  isEnrolled  score
0  He was late to class  Jack        True   2.17
1             Graduated  Nick       False   1.11
2                         Zoe        True   4.12


df2 = pd.DataFrame(d2)

Out[2]: 
                Comment  Name  isEnrolled  score
0  He was late to class  Jack        True   2.17
1           On vacation   Zoe        True   4.12

diff_df(df1, df2)
Out[3]: 
     Comment  Name  isEnrolled  score
1  Graduated  Nick       False   1.11
2              Zoe        True   4.12

diff_df(df2, df1)
Out[4]: 
       Comment Name  isEnrolled  score
1  On vacation  Zoe        True   4.12

# This gives the same result as above
diff_df(df1, df2, how='right')
Out[22]: 
       Comment Name  isEnrolled  score
1  On vacation  Zoe        True   4.12

-1

import pandy jako pd import numpy jako np

df = pd.read_excel ('D: \ HARISH \ DATA SCIENCE \ 1 MY Training \ SAMPLE DATA & projs \ CRICKET DATA \ LISTA ODTWARZACZY IPL \ LISTA ODTWARZACZY IPL _ harish.xlsx')

df1 = srh = df [df ['ZESPÓŁ']. str.contains ("SRH")] df2 = csk = df [df ['ZESPÓŁ']. str.contains ("CSK")]

srh = srh.iloc [:, 0: 2] csk = csk.iloc [:, 0: 2]

csk = csk.reset_index (drop = True) csk

srh = srh.reset_index (drop = True) srh

nowy = pd.concat ([srh, csk], axis = 1)

new.head ()

** TYP ODTWARZACZA TYP ODTWARZACZA

0 David Warner Batsman ... MS Dhoni Kapitan

1 Bhuvaneshwar Kumar Bowler ... Ravindra Jadeja All-Rounder

2 Manish Pandey Batsman ... Suresh Raina All-Rounder

3 Rashid Khan Arman Bowler ... Kedar Jadhav All-Rounder

4 Shikhar Dhawan Batsman… Dwayne Bravo All-Rounder


Typ odtwarzacza Typ odtwarzacza 0 David Warner Batsman MS Dhoni kapitan 1 Bhuvaneshwar Kumar Bowler Ravindra Jadeja wszechstronny 2 Manish Pandey odbijający Suresh Raina wszechstronny 3 Rashid Khan Arman Bowler Kedar Jadhav wszechstronny 4 Shikhar Dhawan Batsman Dwayne Bravo wszechstronny
Harish TRASH

Witaj Harish, proszę sformatuj swoją odpowiedź trochę bardziej, w przeciwnym razie jest dość trudna do odczytania :)
Markus
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.